noinst_HEADERS=alsactl.h
man_MANS=alsactl.1
-alsactl_SOURCES=alsactl.c alsactl_parser.y setup.c alsactl_lexer.l
+alsactl_SOURCES=alsactl.c alsactl_parser.y setup.c merge.c alsactl_lexer.l
YFLAGS=-d
+
+# lexer / parser debug
+#CFLAGS=-pipe -g -DYYDEBUG
+#LFLAGS=-d
+
printf(" from configuration file\n");
}
-static int collect_all(void)
-{
- int idx, err;
- unsigned int card_mask;
-
- card_mask = snd_cards_mask();
- if (!card_mask) {
- error("No soundcards found...");
- return 1;
- }
- soundcard_setup_init();
- for (idx = 0; idx < 32; idx++) {
- if (card_mask & (1 << idx)) { /* find each installed soundcards */
- if ((err = soundcard_setup_collect(idx))) {
- soundcard_setup_done();
- return err;
- }
- }
- }
- return 0;
-}
-
static int store_setup(const char *cardname)
{
int err;
soundcard_setup_init();
for (idx = 0; idx < 32; idx++) {
if (card_mask & (1 << idx)) { /* find each installed soundcards */
- if ((err = soundcard_setup_collect(idx))) {
+ if ((err = soundcard_setup_collect_switches(idx))) {
+ soundcard_setup_done();
+ return err;
+ }
+ if ((err = soundcard_setup_collect_data(idx))) {
soundcard_setup_done();
return err;
}
}
}
+ err = soundcard_setup_write(cfgfile, -1);
+ soundcard_setup_done();
} else {
int cardno;
error("Cannot find soundcard '%s'...", cardname);
return 1;
}
- if ((err = collect_all()))
- return err;
- if ((err = soundcard_setup_load(cfgfile, 1)))
+ if ((err = soundcard_setup_collect_switches(cardno))) {
+ soundcard_setup_done();
return err;
- if ((err = soundcard_setup_collect(cardno))) {
+ }
+ if ((err = soundcard_setup_collect_data(cardno))) {
soundcard_setup_done();
return err;
}
+ err = soundcard_setup_write(cfgfile, cardno);
+ soundcard_setup_done();
}
- err = soundcard_setup_write(cfgfile);
- soundcard_setup_done();
return err;
}
return 1;
}
}
- if ((err = collect_all()))
- return err;
if ((err = soundcard_setup_load(cfgfile, 0)))
return err;
- err = soundcard_setup_process(cardno);
+ if ((err = soundcard_setup_collect_switches(cardno))) {
+ soundcard_setup_done();
+ return err;
+ }
+ if ((err = soundcard_setup_merge_switches(cardno))) {
+ soundcard_setup_done();
+ return err;
+ }
+ if ((err = soundcard_setup_process_switches(cardno))) {
+ soundcard_setup_done();
+ return err;
+ }
+ if ((err = soundcard_setup_collect_data(cardno))) {
+ soundcard_setup_done();
+ return err;
+ }
+ if ((err = soundcard_setup_merge_data(cardno))) {
+ soundcard_setup_done();
+ return err;
+ }
+ if ((err = soundcard_setup_process_data(cardno))) {
+ soundcard_setup_done();
+ return err;
+ }
soundcard_setup_done();
return err;
}
return 0;
}
-
-
struct ctl_switch *switches;
};
-struct mixer_channel {
- int no;
- int direction;
- int voice;
- snd_mixer_channel_info_t info;
- snd_mixer_channel_t data;
- snd_mixer_channel_direction_info_t dinfo[2];
- snd_mixer_channel_direction_t ddata[2];
- struct mixer_channel *next;
+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_channel *channels;
+ struct mixer_element *elements;
struct ctl_switch *switches;
struct mixer *next;
};
};
extern struct soundcard *soundcards;
+extern struct soundcard *rsoundcards; /* read soundcards */
void soundcard_setup_init(void);
void soundcard_setup_done(void);
int soundcard_setup_load(const char *filename, int skip);
-int soundcard_setup_write(const char *filename);
-int soundcard_setup_collect(int cardno);
-int soundcard_setup_process(int cardno);
+int soundcard_setup_write(const char *filename, int cardno);
+int soundcard_setup_collect_switches(int cardno);
+int soundcard_setup_collect_data(int cardno);
+int soundcard_setup_merge_switches(int cardno);
+int soundcard_setup_merge_data(int cardno);
+int soundcard_setup_process_switches(int cardno);
+int soundcard_setup_process_data(int cardno);
+
+char *mixer_element_id(snd_mixer_eid_t *eid);
%{
#include "alsactl.h"
+
+struct bytearray {
+ unsigned char *data;
+ size_t datalen;
+};
+
#include "alsactl_parser.h"
#define YY_NO_UNPUT
"["|"]" return yytext[0];
")"[ \t]*"{" return L_DOUBLE1;
"," return yytext[0];
+"=" return yytext[0];
/* tokens */
soundcard return L_SOUNDCARD;
control return L_CONTROL;
mixer return L_MIXER;
-channel return L_CHANNEL;
-stereo return L_STEREO;
-mono return L_MONO;
+element return L_ELEMENT;
switch return L_SWITCH;
rawdata return L_RAWDATA;
pcm return L_PCM;
gstatus return L_GSTATUS;
enable return L_ENABLE;
disable return L_DISABLE;
-mute return L_MUTE;
-swap return L_SWAP;
+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;
+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 */
/* integers */
-[0-9]+ { yylval.i_value = atoi( yytext ); return L_INTEGER; }
+[0-9]+ { yylval.i_value = atoi(yytext); return L_INTEGER; }
0x[0-9a-f]+ { char *end;
- yylval.i_value = strtol( yytext, &end, 0 );
+ yylval.i_value = strtol(yytext, &end, 0);
return L_INTEGER; }
/* byte array */
char *p = yytext + 1, x[3];
unsigned char *d;
int val;
- yylval.a_value = d = (unsigned char *)malloc( 32 );
- while ( p ) {
- strncpy( x, p, 2 ); x[2] = '\0';
- sscanf( x, "%02x", &val );
- *d++ = val;
+ yylval.a_value.data = d = (unsigned char *)malloc( 32 );
+ yylval.a_value.datalen = 0;
+ while (p) {
+ strncpy(x, p, 2); x[2] = '\0';
+ sscanf(x, "%02x", &val);
+ *d++ = val;
+ ++yylval.a_value.datalen;
}
return L_BYTEARRAY; }
/* strings */
-\"[^\"]*\" { yytext[ strlen( yytext ) - 1 ] = 0;
- yylval.s_value = strdup( &yytext[ 1 ] );
+\"[^\"]*\" { yytext[strlen(yytext) - 1] = 0;
+ yylval.s_value = strdup(&yytext[1]);
return L_STRING; }
-\'[^\']*\' { yytext[ strlen( yytext ) - 1 ] = 0;
- yylval.s_value = strdup( &yytext[ 1 ] );
+\'[^\']*\' { yytext[strlen(yytext) - 1] = 0;
+ yylval.s_value = strdup(&yytext[1]);
return L_STRING; }
-[a-z0-9/\~@-Za-z_\+=:\.]+ { yylval.s_value = strdup( yytext );
+[a-z0-9/\~@-Za-z_]+ { yylval.s_value = strdup(yytext);
return L_STRING; }
-$[a-z0-9/\~@-Za-z_\+=:\.]+ { yylval.s_value = strdup( getenv( &yytext[ 1 ] ) );
+$[a-z0-9/\~@-Za-z_]+ { yylval.s_value = strdup(getenv(&yytext[1]));
return L_STRING; }
/* comments & whitespaces */
extern int linecount;
extern FILE *yyin;
+ /* structure for byte arrays */
+
+struct bytearray {
+ unsigned char *data;
+ size_t datalen;
+};
+
/* local functions */
static void yyerror(char *, ...);
-static void select_soundcard(char *name);
-static void select_mixer(char *name);
-static void select_pcm(char *name);
-static void select_rawmidi(char *name);
-
-static void select_mixer_channel(char *name);
-static void select_mixer_direction(int direction);
-static void select_mixer_voice(int voice);
-static void set_mixer_volume(int volume);
-static void set_mixer_flags(int flags);
-static void select_mixer_channel_end(void);
-
-#define SWITCH_CONTROL 0
-#define SWITCH_MIXER 1
-#define SWITCH_PCM 2
-#define SWITCH_RAWMIDI 3
-
-static void select_control_switch(char *name);
-static void select_mixer_switch(char *name);
-static void select_pcm_playback_switch(char *name);
-static void select_pcm_record_switch(char *name);
-static void select_rawmidi_output_switch(char *name);
-static void select_rawmidi_input_switch(char *name);
+static void build_soundcard(char *name);
+static void build_mixer(char *name);
+static void build_pcm(char *name);
+static void build_rawmidi(char *name);
+
+static void build_mixer_element(char *name, int index, int etype);
+
+static void build_control_switch(char *name);
+static void build_mixer_switch(char *name);
+static void build_pcm_playback_switch(char *name);
+static void build_pcm_record_switch(char *name);
+static void build_rawmidi_output_switch(char *name);
+static void build_rawmidi_input_switch(char *name);
+
+static void mixer_switch1(int end);
+static void mixer_switch1_value(int val);
+static void mixer_switch2(int end);
+static void mixer_switch2_value(int val);
+static void mixer_switch3(int end);
+static void mixer_switch3_value(int val);
+static void mixer_volume1(int end);
+static void mixer_volume1_value(int val);
+static void mixer_3d_effect1(int end);
+static void mixer_3d_effect1_value(unsigned int effect, int val);
+static void mixer_accu3(int end);
+static void mixer_accu3_value(int val);
+static void mixer_mux1(int end);
+static void mixer_mux1_value(char *str, int index, int type);
+static void mixer_mux2(int end);
+static void mixer_mux2_value(char *str, int index, int type);
+static void mixer_tone_control1(int end);
+static void mixer_tone_control1_value(unsigned int effect, int val);
static void set_switch_boolean(int val);
static void set_switch_integer(int val);
+static void set_switch_bytearray(struct bytearray val);
static void set_switch_iec958ocs_begin(int end);
static void set_switch_iec958ocs(int idx, unsigned short val, unsigned short mask);
static struct mixer *Xmixer = NULL;
static struct pcm *Xpcm = NULL;
static struct rawmidi *Xrawmidi = NULL;
-static struct mixer_channel *Xchannel = NULL;
-static int Xswitchtype = SWITCH_CONTROL;
-static int *Xswitchchange = NULL;
-static snd_switch_t *Xswitch = NULL;
+static struct mixer_element *Xelement = NULL;
+static struct ctl_switch *Xswitch = NULL;
static unsigned int Xswitchiec958ocs = 0;
static unsigned short Xswitchiec958ocs1[16];
int b_value;
int i_value;
char *s_value;
- unsigned char *a_value;
+ struct bytearray a_value;
};
%token <b_value> L_TRUE L_FALSE
/* misc */
%token L_DOUBLE1
/* other keywords */
-%token L_SOUNDCARD L_MIXER L_CHANNEL L_STEREO L_MONO L_SWITCH L_RAWDATA
-%token L_CONTROL L_PCM L_RAWMIDI L_PLAYBACK L_RECORD L_OUTPUT L_INPUT
+%token L_SOUNDCARD L_MIXER L_ELEMENT L_SWITCH L_RAWDATA
+%token L_CONTROL L_PCM L_RAWMIDI L_PLAYBACK L_RECORD L_INPUT L_OUTPUT
+%token L_SWITCH1 L_SWITCH2 L_SWITCH3 L_VOLUME1 L_3D_EFFECT1 L_ACCU3
+%token L_MUX1 L_MUX2 L_TONE_CONTROL1
%token L_IEC958OCS L_3D L_RESET L_USER L_VALID L_DATA L_PROTECT L_PRE2
-%token L_FSUNLOCK L_TYPE L_GSTATUS L_ENABLE L_DISABLE L_MUTE L_SWAP
+%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_FEEDBACK L_BASS L_TREBLE
+
%type <b_value> boolean
%type <i_value> integer
%type <s_value> string
-%type <a_value> bytearray
+%type <a_value> rawdata
%%
| lines line
;
-line : L_SOUNDCARD '(' string { select_soundcard( $3 ); } L_DOUBLE1 soundcards { select_soundcard( NULL ); } '}'
- | error { yyerror( "unknown keyword in top level" ); }
+line : L_SOUNDCARD '(' string { build_soundcard($3); }
+ L_DOUBLE1 soundcards '}' { build_soundcard(NULL); }
+ | error { yyerror("unknown keyword in top level"); }
;
soundcards : soundcard
;
soundcard : L_CONTROL '{' controls '}'
- | L_MIXER '(' string { select_mixer( $3 ); } L_DOUBLE1 mixers { select_mixer( NULL ); } '}'
- | L_PCM '(' string { select_pcm( $3 ); } L_DOUBLE1 pcms { select_pcm( NULL ); } '}'
- | L_RAWMIDI '(' string { select_rawmidi( $3 ); } L_DOUBLE1 rawmidis { select_rawmidi( NULL ); } '}'
- | error { yyerror( "unknown keyword in soundcard{} level" ); }
+ | L_MIXER '(' string { build_mixer($3); }
+ L_DOUBLE1 mixers '}' { build_mixer(NULL); }
+ | L_PCM '(' string { build_pcm($3); }
+ L_DOUBLE1 pcms '}' { build_pcm(NULL); }
+ | L_RAWMIDI '(' string { build_rawmidi($3); }
+ L_DOUBLE1 rawmidis '}' { build_rawmidi(NULL); }
+ | error { yyerror( "an unknown keyword in the soundcard{} level"); }
;
controls : control
| controls control
;
-control : L_SWITCH '(' string { select_control_switch( $3 ); } ',' switches ')' { select_control_switch( NULL ); }
- | error { yyerror( "unknown keyword in control{} level" ); }
+control : L_SWITCH '(' string { build_control_switch($3); }
+ ',' switches ')' { build_control_switch(NULL); }
+ | error { yyerror("an unknown keyword in the control{} level"); }
;
+
mixers : mixer
| mixers mixer
;
-mixer : L_CHANNEL '(' string { select_mixer_channel( $3 ); }
- ',' settings ')' { select_mixer_channel_end();
- select_mixer_channel( NULL ); }
- | L_SWITCH '(' string { select_mixer_switch( $3 ); }
- ',' switches ')' { select_mixer_switch( NULL ); }
- | error { yyerror( "unknown keyword in mixer level" ); }
+mixer : L_ELEMENT '(' string
+ ',' integer ',' integer { build_mixer_element($3, $5, $7); }
+ ',' etype ')' { build_mixer_element(NULL, -1, -1); }
+ | L_SWITCH '(' string { build_mixer_switch($3); }
+ ',' switches ')' { build_mixer_switch(NULL); }
+ | error { yyerror("an unknown keyword in the mixer level"); }
+ ;
+
+
+etype : L_SWITCH1 '(' { mixer_switch1(0); }
+ m_switch1 ')' { mixer_switch1(1); }
+ | L_SWITCH2 '(' { mixer_switch2(0); }
+ m_switch2 ')' { mixer_switch2(1); }
+ | L_SWITCH3 '(' { mixer_switch3(0); }
+ m_switch3 ')' { mixer_switch3(1); }
+ | L_VOLUME1 '(' { mixer_volume1(0); }
+ m_volume1 ')' { mixer_volume1(1); }
+ | L_3D_EFFECT1 '(' { mixer_3d_effect1(0); }
+ m_3d_effect1 ')' { mixer_3d_effect1(1); }
+ | L_ACCU3 '(' { mixer_accu3(0); }
+ m_accu3 ')' { mixer_accu3(1); }
+ | L_MUX1 '(' { mixer_mux1(0); }
+ m_mux1 ')' { mixer_mux1(1); }
+ | L_MUX2 '(' { mixer_mux2(0); }
+ L_ELEMENT '('
+ string ','
+ integer ','
+ integer ')' { mixer_mux2_value($6, $8, $10); }
+ ')' { mixer_mux2(1); }
+ | L_TONE_CONTROL1 '(' { mixer_tone_control1(0); }
+ m_tone_control1 ')' { mixer_tone_control1(1); }
+ | error { yyerror("an unknown keyword in the mixer element level"); }
+ ;
+
+m_switch1 : m_switch1_0
+ | m_switch1 ',' m_switch1_0
+ ;
+
+m_switch1_0 : boolean { mixer_switch1_value($1); }
+ | error { yyerror("an unknown keyword in the Switch1 element level"); }
+ ;
+
+m_switch2 : m_switch2_0
+ | m_switch2 ',' m_switch2_0
+ ;
+
+m_switch2_0 : boolean { mixer_switch2_value($1); }
+ | error { yyerror("an unknown keyword in the Switch2 element level"); }
+ ;
+
+m_switch3 : m_switch3_0
+ | m_switch3 ',' m_switch3_0
;
+m_switch3_0 : boolean { mixer_switch3_value($1); }
+ | error { yyerror("an unknown keyword in the Switch3 element level"); }
+ ;
+
+m_volume1 : m_volume1_0
+ | m_volume1 ',' m_volume1_0
+ ;
+
+m_volume1_0 : integer { mixer_volume1_value($1); }
+ | error { yyerror("an unknown keyword in the Volume1 element level"); }
+ ;
+
+m_3d_effect1 : m_3d_effect1_0
+ | m_3d_effect1 ',' m_3d_effect1_0
+ ;
+
+m_3d_effect1_0 : L_SW '=' boolean { mixer_3d_effect1_value(SND_MIXER_EFF1_SW, $3); }
+ | L_MONO_SW '=' boolean { mixer_3d_effect1_value(SND_MIXER_EFF1_MONO_SW, $3); }
+ | L_WIDE '=' integer { mixer_3d_effect1_value(SND_MIXER_EFF1_WIDE, $3); }
+ | L_VOLUME '=' integer { mixer_3d_effect1_value(SND_MIXER_EFF1_VOLUME, $3); }
+ | L_CENTER '=' integer { mixer_3d_effect1_value(SND_MIXER_EFF1_CENTER, $3); }
+ | L_SPACE '=' integer { mixer_3d_effect1_value(SND_MIXER_EFF1_SPACE, $3); }
+ | L_DEPTH '=' integer { mixer_3d_effect1_value(SND_MIXER_EFF1_DEPTH, $3); }
+ | L_DELAY '=' integer { mixer_3d_effect1_value(SND_MIXER_EFF1_DELAY, $3); }
+ | L_FEEDBACK '=' integer { mixer_3d_effect1_value(SND_MIXER_EFF1_FEEDBACK, $3); }
+ | error { yyerror("an unknown keyword in the 3D Effect1 element level"); }
+ ;
-settings: setting
- | settings ',' setting
+m_accu3 : m_accu3_0
+ | m_accu3 ',' m_accu3_0
;
-setting : L_OUTPUT { select_mixer_direction(OUTPUT); }
- dsetting
- | L_INPUT { select_mixer_direction(INPUT); }
- dsetting
- | error { yyerror( "unknown keyword in mixer channel level" ); }
+m_accu3_0 : integer { mixer_accu3_value($1); }
+ | error { yyerror("an unknown keyword in the Accu3 element level"); }
;
-dsetting: L_STEREO '(' { select_mixer_voice(LEFT); }
- vsettings ',' { select_mixer_voice(RIGHT); }
- vsettings ')'
- | L_MONO '(' { select_mixer_voice(LEFT|RIGHT); }
- vsettings ')'
- | error { yyerror( "unknown keyword in mixer direction level" ); }
+m_mux1 : m_mux1_0
+ | m_mux1 ',' m_mux1_0
;
-vsettings: vsetting
- | vsettings vsetting
+m_mux1_0 : L_ELEMENT '(' string
+ ',' integer ','
+ integer ')' { mixer_mux1_value($3, $5, $7); }
+ | error { yyerror("an unknown keyword in the Mux1 element level"); }
;
-vsetting: L_INTEGER { set_mixer_volume($1); }
- | L_MUTE { set_mixer_flags(SND_MIXER_DFLG_MUTE); }
- | L_SWAP { set_mixer_flags(SND_MIXER_DFLG_SWAP); }
- | error { yyerror( "unknown keyword in mixer voice 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_RECORD '{' records '}'
- | error { yyerror( "unknown keyword in pcm{} section" ); }
+ | error { yyerror("an unknown keyword in the pcm{} section"); }
;
playbacks : playback
| playbacks playback
;
-playback : L_SWITCH '(' string { select_pcm_playback_switch( $3 ); } ',' switches ')' { select_pcm_playback_switch( NULL ); }
- | error { yyerror( "unknown keyword in playback{} section" ); }
+playback : L_SWITCH '(' string { build_pcm_playback_switch($3); }
+ ',' switches ')' { build_pcm_playback_switch(NULL); }
+ | error { yyerror("an unknown keyword in the playback{} section"); }
;
records : record
| records record
;
-record : L_SWITCH '(' string { select_pcm_record_switch( $3 ); } ',' switches ')' { select_pcm_record_switch( NULL ); }
- | error { yyerror( "unknown keyword in record{} section" ); }
+record : L_SWITCH '(' string { build_pcm_record_switch($3); }
+ ',' switches ')' { build_pcm_record_switch(NULL); }
+ | error { yyerror("an unknown keyword in the record{} section"); }
;
rawmidis : rawmidi
| inputs input
;
-input : L_SWITCH '(' string { select_rawmidi_input_switch( $3 ); } ',' switches ')' { select_rawmidi_input_switch( NULL ); }
- | error { yyerror( "unknown keyword in input{} section" ); }
+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 { select_rawmidi_output_switch( $3 ); } ',' switches ')' { select_rawmidi_output_switch( NULL ); }
- | error { yyerror( "unknown keyword in output{} section" ); }
+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 : L_TRUE { set_switch_boolean( 1 ); }
- | L_FALSE { set_switch_boolean( 0 ); }
- | L_INTEGER { set_switch_integer( $1 ); }
- | L_IEC958OCS '(' { set_switch_iec958ocs_begin( 0 ); } iec958ocs { set_switch_iec958ocs_begin( 1 ); } ')'
- | error { yyerror( "unknown keyword in switch() data parameter" ); }
+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
+ | iec958ocs ',' iec958ocs1
;
iec958ocs1 : L_ENABLE { set_switch_iec958ocs( 0, 1, 0 ); }
| 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( "unknown keyword in iec958ocs1() arguments" ); }
+ | error { yyerror( "an unknown keyword in the iec958ocs1() arguments" ); }
;
boolean : L_TRUE { $$ = 1; }
| L_FALSE { $$ = 0; }
- | error { yyerror( "unknown boolean value" ); }
;
integer : L_INTEGER { $$ = $1; }
- | error { yyerror( "unknown integer value" ); }
;
string : L_STRING { $$ = $1; }
- | error { yyerror( "unknown string value" ); }
;
-bytearray : L_BYTEARRAY { $$ = $1; }
- | error { yyerror( "unknown byte array value" ); }
+rawdata : L_RAWDATA '(' L_BYTEARRAY ')' { $$ = $3; }
+ | L_RAWDATA error { yyerror( "malformed rawdata value" ); }
;
%%
exit(1);
}
-static void select_soundcard(char *name)
+static void error_nomem(void)
+{
+ yyerror("No enough memory...\n");
+}
+
+static void build_soundcard(char *name)
{
struct soundcard *soundcard;
Xsoundcard = NULL;
return;
}
- for (soundcard = soundcards; soundcard; soundcard = soundcard->next)
- if (!strcmp(soundcard->control.hwinfo.id, name)) {
- Xsoundcard = soundcard;
- free(name);
- return;
- }
- yyerror("Cannot find soundcard '%s'...", name);
+ Xsoundcard = (struct soundcard *)malloc(sizeof(struct soundcard));
+ if (!Xsoundcard) {
+ free(name);
+ error_nomem();
+ return;
+ }
+ bzero(Xsoundcard, sizeof(*Xsoundcard));
+ for (soundcard = rsoundcards; soundcard && soundcard->next; soundcard = soundcard->next);
+ if (soundcard) {
+ soundcard->next = Xsoundcard;
+ } else {
+ rsoundcards = Xsoundcard;
+ }
+ strncpy(Xsoundcard->control.hwinfo.id, name, sizeof(Xsoundcard->control.hwinfo.id));
free(name);
}
-static void select_mixer(char *name)
+static void build_mixer(char *name)
{
struct mixer *mixer;
Xmixer = NULL;
return;
}
- for (mixer = Xsoundcard->mixers; mixer; mixer = mixer->next)
- if (!strcmp(mixer->info.name, name)) {
- Xmixer = mixer;
- free(name);
- return;
- }
- yyerror("Cannot find mixer '%s' for soundcard '%s'...", name, Xsoundcard->control.hwinfo.id);
+ Xmixer = (struct mixer *)malloc(sizeof(struct pcm));
+ if (!Xmixer) {
+ free(name);
+ error_nomem();
+ return;
+ }
+ bzero(Xmixer, sizeof(*Xmixer));
+ for (mixer = Xsoundcard->mixers; mixer && mixer->next; mixer = mixer->next);
+ if (mixer) {
+ mixer->next = Xmixer;
+ } else {
+ Xsoundcard->mixers = Xmixer;
+ }
+ strncpy(Xmixer->info.name, name, sizeof(Xmixer->info.name));
free(name);
}
-static void select_pcm(char *name)
+static void build_pcm(char *name)
{
struct pcm *pcm;
Xpcm = NULL;
return;
}
- for (pcm = Xsoundcard->pcms; pcm; pcm = pcm->next)
- if (!strcmp(pcm->info.name, name)) {
- Xpcm = pcm;
- free(name);
- return;
- }
- yyerror("Cannot find pcm device '%s' for soundcard '%s'...", name, Xsoundcard->control.hwinfo.id);
+ 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 select_rawmidi(char *name)
+static void build_rawmidi(char *name)
{
struct rawmidi *rawmidi;
Xrawmidi = NULL;
return;
}
- for (rawmidi = Xsoundcard->rawmidis; rawmidi; rawmidi = rawmidi->next)
- if (!strcmp(rawmidi->info.name, name)) {
- Xrawmidi = rawmidi;
- free(name);
- return;
- }
- yyerror("Cannot find rawmidi device '%s' for soundcard '%s'...", name, Xsoundcard->control.hwinfo.id);
+ 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 select_mixer_channel(char *name)
+static void build_mixer_element(char *name, int index, int etype)
{
- struct mixer_channel *channel;
+ struct mixer_element *element;
if (!name) {
- Xchannel = NULL;
+ Xelement = NULL;
return;
}
- for (channel = Xmixer->channels; channel; channel = channel->next)
- if (!strcmp(channel->info.name, name)) {
- Xchannel = channel;
- Xchannel->ddata[OUTPUT].flags = 0;
- Xchannel->ddata[INPUT].flags = 0;
- free(name);
+ 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;
}
- yyerror("Cannot find mixer channel '%s'...", name);
- free(name);
+ 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 select_mixer_direction(int direction)
+static void mixer_switch2(int end)
{
- Xchannel->direction = direction;
+ 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 select_mixer_voice(int voice)
+static void mixer_volume1(int end)
{
- Xchannel->voice = voice;
+ mixer_type_check(SND_MIXER_ETYPE_VOLUME1);
}
-static void set_mixer_volume(int volume)
+static void mixer_volume1_value(int val)
{
- snd_mixer_channel_direction_info_t *i = &Xchannel->dinfo[Xchannel->direction];
- snd_mixer_channel_direction_t *d = &Xchannel->ddata[Xchannel->direction];
- if (Xchannel->voice & LEFT) {
- if (i->min > volume || i->max < volume)
- yyerror("Value out of range (%i-%i)...", i->min, i->max);
- d->left = volume;
+ int *ptr;
+
+ if (Xelement->element.data.volume1.voices_size <= Xelement->element.data.volume1.voices) {
+ Xelement->element.data.volume1.voices_size += 4;
+ ptr = (int *)realloc(Xelement->element.data.volume1.pvoices, Xelement->element.data.volume1.voices_size * sizeof(int));
+ if (ptr == NULL) {
+ error_nomem();
+ return;
+ }
+ Xelement->element.data.volume1.pvoices = ptr;
}
- if (Xchannel->voice & RIGHT) {
- if (i->min > volume || i->max < volume)
- yyerror("Value out of range (%i-%i)...", i->min, i->max);
- d->right = volume;
+ Xelement->element.data.volume1.pvoices[Xelement->element.data.volume1.voices++] = 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;
+ case SND_MIXER_EFF1_MONO_SW:
+ Xelement->element.data.teffect1.mono_sw = val ? 1 : 0;
+ break;
+ case SND_MIXER_EFF1_WIDE:
+ Xelement->element.data.teffect1.wide = val;
+ break;
+ case SND_MIXER_EFF1_VOLUME:
+ Xelement->element.data.teffect1.volume = val;
+ break;
+ case SND_MIXER_EFF1_CENTER:
+ Xelement->element.data.teffect1.center = val;
+ break;
+ case SND_MIXER_EFF1_SPACE:
+ Xelement->element.data.teffect1.space = val;
+ break;
+ case SND_MIXER_EFF1_DEPTH:
+ Xelement->element.data.teffect1.depth = val;
+ break;
+ case SND_MIXER_EFF1_DELAY:
+ Xelement->element.data.teffect1.delay = val;
+ break;
+ case SND_MIXER_EFF1_FEEDBACK:
+ Xelement->element.data.teffect1.feedback = val;
+ break;
+ default:
+ yyerror("Unknown effect 0x%x\n", effect);
}
+}
+
+static void mixer_accu3(int end)
+{
+ mixer_type_check(SND_MIXER_ETYPE_ACCU3);
}
-static void set_mixer_flags(int flags)
+static void mixer_accu3_value(int val)
{
- snd_mixer_channel_direction_t *d = &Xchannel->ddata[Xchannel->direction];
- if (Xchannel->voice & LEFT) {
- if (flags & SND_MIXER_DFLG_MUTE)
- d->flags |= SND_MIXER_DFLG_MUTE_LEFT;
- if (flags & SND_MIXER_DFLG_SWAP)
- d->flags |= SND_MIXER_DFLG_LTOR;
+ int *ptr;
+
+ if (Xelement->element.data.accu3.voices_size <= Xelement->element.data.accu3.voices) {
+ Xelement->element.data.accu3.voices_size += 4;
+ ptr = (int *)realloc(Xelement->element.data.accu3.pvoices, Xelement->element.data.accu3.voices_size * sizeof(int));
+ if (ptr == NULL) {
+ error_nomem();
+ return;
+ }
+ Xelement->element.data.accu3.pvoices = ptr;
}
- if (Xchannel->voice & RIGHT) {
- if (flags & SND_MIXER_DFLG_MUTE)
- d->flags |= SND_MIXER_DFLG_MUTE_RIGHT;
- if (flags & SND_MIXER_DFLG_SWAP)
- d->flags |= SND_MIXER_DFLG_RTOL;
+ Xelement->element.data.accu3.pvoices[Xelement->element.data.accu3.voices++] = 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.output_size <= Xelement->element.data.mux1.output) {
+ Xelement->element.data.mux1.output_size += 4;
+ ptr = (snd_mixer_eid_t *)realloc(Xelement->element.data.mux1.poutput, Xelement->element.data.mux1.output_size * sizeof(snd_mixer_eid_t));
+ if (ptr == NULL) {
+ error_nomem();
+ free(name);
+ return;
+ }
+ Xelement->element.data.mux1.poutput = ptr;
}
+ eid = &Xelement->element.data.mux1.poutput[Xelement->element.data.mux1.output++];
+ 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 select_mixer_channel_end(void)
+static void mixer_mux2_value(char *name, int index, int type)
{
+ snd_mixer_eid_t *eid;
+
+ eid = &Xelement->element.data.mux2.output;
+ 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 find_switch(int xtype, struct ctl_switch *first, char *name, char *err)
+static void mixer_tone_control1_value(unsigned int effect, int val)
+{
+ 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;
- Xswitchchange = NULL;
return;
}
- for (sw = first; sw; sw = sw->next) {
- if (!strcmp(sw -> s.name, name)) {
- Xswitchtype = xtype;
- Xswitchchange = &sw->change;
- Xswitch = &sw->s;
- free(name);
- 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;
}
- yyerror("Cannot find %s switch '%s'...", err, name);
+ strncpy(Xswitch->s.name, name, sizeof(Xswitch->s.name));
free(name);
}
-static void select_control_switch(char *name)
+static void build_control_switch(char *name)
{
- find_switch(SWITCH_CONTROL, Xsoundcard->control.switches, name, "control");
+ build_switch(&Xsoundcard->control.switches, name);
}
-static void select_mixer_switch(char *name)
+static void build_mixer_switch(char *name)
{
- find_switch(SWITCH_MIXER, Xmixer->switches, name, "mixer");
+ build_switch(&Xmixer->switches, name);
}
-static void select_pcm_playback_switch(char *name)
+static void build_pcm_playback_switch(char *name)
{
- find_switch(SWITCH_PCM, Xpcm->pswitches, name, "pcm playback");
+ build_switch(&Xpcm->pswitches, name);
}
-static void select_pcm_record_switch(char *name)
-{
- find_switch(SWITCH_PCM, Xpcm->rswitches, name, "pcm record");
+static void build_pcm_record_switch(char *name)
+{
+ build_switch(&Xpcm->rswitches, name);
}
-static void select_rawmidi_output_switch(char *name)
+static void build_rawmidi_output_switch(char *name)
{
- find_switch(SWITCH_RAWMIDI, Xrawmidi->oswitches, name, "rawmidi output");
+ build_switch(&Xrawmidi->oswitches, name);
}
-static void select_rawmidi_input_switch(char *name)
+static void build_rawmidi_input_switch(char *name)
{
- find_switch(SWITCH_RAWMIDI, Xrawmidi->iswitches, name, "rawmidi input");
+ build_switch(&Xrawmidi->iswitches, name);
}
static void set_switch_boolean(int val)
{
- snd_switch_t *sw = Xswitch;
- unsigned int xx;
-
- if (sw->type != SND_SW_TYPE_BOOLEAN)
- yyerror("Switch '%s' isn't boolean type...", sw->name);
- xx = val ? 1 : 0;
- if (sw->value.enable != xx)
- *Xswitchchange = 1;
- sw->value.enable = xx;
-#if 0
- printf("name = '%s', sw->value.enable = %i\n", sw->name, xx);
-#endif
+ Xswitch->s.type = SND_SW_TYPE_BOOLEAN;
+ Xswitch->s.value.enable = val ? 1 : 0;
}
static void set_switch_integer(int val)
{
- snd_switch_t *sw = Xswitch;
unsigned int xx;
- if (sw->type != SND_SW_TYPE_BYTE &&
- sw->type != SND_SW_TYPE_WORD &&
- sw->type != SND_SW_TYPE_DWORD)
- yyerror("Switch '%s' isn't integer type...", sw->name);
- if (val < sw->low || val > sw->high)
- yyerror("Value for switch '%s' out of range (%i-%i)...\n", sw->name, sw->low, sw->high);
+ Xswitch->s.type = SND_SW_TYPE_DWORD;
xx = val;
- if (memcmp(&sw->value, &xx, sizeof(xx)))
- *Xswitchchange = 1;
- memcpy(&sw->value, &xx, sizeof(xx));
+ memcpy(&Xswitch->s.value, &xx, sizeof(xx));
}
-static void set_switch_iec958ocs_begin(int end)
+static void set_switch_bytearray(struct bytearray val)
{
- snd_switch_t *sw = Xswitch;
+ Xswitch->s.type = SND_SW_TYPE_LAST + 1;
+ if (val.datalen > 32)
+ yyerror("Byte array too large for switch.");
+
+ memcpy(Xswitch->s.value.data8, val.data, val.datalen);
+}
+
+static void set_switch_iec958ocs_begin(int end)
+{
if (end) {
- if (Xswitchiec958ocs != sw->value.enable) {
- sw->value.enable = Xswitchiec958ocs;
- *Xswitchchange = 1;
- }
- if (Xswitchiec958ocs1[4] != sw->value.data16[4]) {
- sw->value.data16[4] = Xswitchiec958ocs1[4];
- *Xswitchchange = 1;
- }
- if (Xswitchiec958ocs1[5] != sw->value.data16[5]) {
- sw->value.data16[5] = Xswitchiec958ocs1[5];
- *Xswitchchange = 1;
- }
+ 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,
#endif
return;
}
- if (Xswitchtype != SWITCH_MIXER || sw->type != SND_SW_TYPE_BOOLEAN ||
- strcmp(sw->name, SND_MIXER_SW_IEC958OUT))
- yyerror("Switch '%s' cannot store IEC958 information for Cirrus Logic chips...", sw->name);
- if (sw->value.data32[1] != (('C' << 8) | 'S'))
- yyerror("Switch '%s' doesn't have Cirrus Logic signature!!!", sw->name);
+ 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 */
--- /dev/null
+/*
+ * Advanced Linux Sound Architecture Control Program
+ * Copyright (c) 1999 by Jaroslav Kysela <perex@jcu.cz>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "alsactl.h"
+
+static char *sw_id(const char *name, int cardno, int devno, const char *id)
+{
+ static char str[256];
+
+ sprintf(str, "%s %s card %i", name, id, cardno);
+ if (devno >= 0)
+ sprintf(str + strlen(str)," device %i", devno);
+ return str;
+}
+
+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;
+ }
+ if (csw->s.value.enable != usw->s.value.enable) {
+ csw->change = 1;
+ csw->s.value.enable = usw->s.value.enable;
+ }
+ if (!strncmp(csw->s.name, SND_MIXER_SW_IEC958_OUTPUT, sizeof(csw->s.name))) {
+ if (usw->s.value.data32[1] == (('C' << 8) | 'S')) {
+ if (csw->s.value.data16[4] != usw->s.value.data16[4] ||
+ csw->s.value.data16[5] != usw->s.value.data16[5]) {
+ csw->change = 1;
+ csw->s.value.data16[4] = usw->s.value.data16[4];
+ csw->s.value.data16[5] = usw->s.value.data16[5];
+ }
+ }
+ }
+ break;
+ case SND_SW_TYPE_BYTE:
+ if (usw->s.type != SND_SW_TYPE_DWORD) {
+ error("A wrong type for the switch %s. The type byte is expected. Skipping...", sw_id(usw->s.name, cardno, devno, id));
+ return 1;
+ }
+ if (csw->s.low > usw->s.value.data32[0] ||
+ csw->s.high < usw->s.value.data32[0]) {
+ error("The value %u for the switch %s is out of range %i-%i.", usw->s.value.data32[0], sw_id(usw->s.name, cardno, devno, id), csw->s.low, csw->s.high);
+ return 1;
+ }
+ if (csw->s.value.data8[0] != (unsigned char)usw->s.value.data32[0]) {
+ csw->change = 1;
+ csw->s.value.data8[0] = (unsigned char)usw->s.value.data32[0];
+ }
+ break;
+ case SND_SW_TYPE_WORD:
+ if (usw->s.type != SND_SW_TYPE_DWORD) {
+ error("A wrong type for the switch %s. The type word is expected. Skipping...", sw_id(usw->s.name, cardno, devno, id));
+ return 1;
+ }
+ if (csw->s.low > usw->s.value.data32[0] ||
+ csw->s.high < usw->s.value.data32[0]) {
+ error("The value %u for the switch %s is out of range %i-%i.", usw->s.value.data32[0], sw_id(usw->s.name, cardno, devno, id), csw->s.low, csw->s.high);
+ return 1;
+ }
+ if (csw->s.value.data16[0] != (unsigned short)usw->s.value.data32[0]) {
+ csw->change = 1;
+ csw->s.value.data16[0] = (unsigned short)usw->s.value.data32[0];
+ }
+ break;
+ case SND_SW_TYPE_DWORD:
+ if (usw->s.type != SND_SW_TYPE_DWORD) {
+ error("A wrong type for the switch %s. The type dword is expected. Skipping...", sw_id(usw->s.name, cardno, devno, id));
+ return 1;
+ }
+ if (csw->s.low > usw->s.value.data32[0] ||
+ csw->s.high < usw->s.value.data32[0]) {
+ error("The value %u for the switch %s is out of range %i-%i.", usw->s.value.data32[0], sw_id(usw->s.name, cardno, devno, id), csw->s.low, csw->s.high);
+ return 1;
+ }
+ if (csw->s.value.data32[0] != usw->s.value.data32[0]) {
+ csw->change = 1;
+ csw->s.value.data32[0] = usw->s.value.data32[0];
+ }
+ break;
+ default:
+ error("The switch type %i is not known.", csw->s.type);
+ }
+ return 0;
+}
+
+static int soundcard_setup_merge_sw(struct ctl_switch *csw, struct ctl_switch *usw, int cardno, int devno, const char *id)
+{
+ struct ctl_switch *csw1;
+
+ for ( ; usw; usw = usw->next) {
+ for (csw1 = csw; csw1; csw1 = csw1->next) {
+ if (!strncmp(csw1->s.name, usw->s.name, sizeof(csw1->s.name))) {
+ merge_one_sw(csw1, usw, cardno, devno, id);
+ break;
+ }
+ }
+ if (!csw1) {
+ error("Cannot find the switch %s...", sw_id(usw->s.name, cardno, devno, id));
+ }
+ }
+ return 0;
+}
+
+int soundcard_setup_merge_switches(int cardno)
+{
+ struct soundcard *soundcard, *rsoundcard;
+ struct mixer *mixer, *rmixer;
+ struct pcm *pcm, *rpcm;
+ struct rawmidi *rawmidi, *rrawmidi;
+
+ for (rsoundcard = rsoundcards; rsoundcard; rsoundcard = rsoundcard->next) {
+ for (soundcard = soundcards; soundcard; soundcard = soundcard->next) {
+ 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;
+ soundcard_setup_merge_sw(soundcard->control.switches, rsoundcard->control.switches, soundcard->no, -1, "control");
+ for (rmixer = rsoundcard->mixers; rmixer; rmixer = rmixer->next) {
+ for (mixer = soundcard->mixers; mixer; mixer = rmixer->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 = rsoundcard->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 record");
+ }
+ 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 voices.", 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.voices != uelement->element.data.volume1.voices) {
+ error("Element %s has got a wrong count of voices.", element_id(&celement->element.eid, cardno, devno, id));
+ return 1;
+ }
+ tmp = celement->element.data.volume1.voices * sizeof(int);
+ memcpy(celement->element.data.volume1.pvoices, uelement->element.data.volume1.pvoices, tmp);
+ break;
+ case SND_MIXER_ETYPE_VOLUME2:
+ if (celement->element.data.volume2.avoices != uelement->element.data.volume2.avoices) {
+ error("Element %s has got a wrong count of voices.", element_id(&celement->element.eid, cardno, devno, id));
+ return 1;
+ }
+ tmp = celement->element.data.volume2.avoices * sizeof(int);
+ memcpy(celement->element.data.volume2.pavoices, uelement->element.data.volume2.pavoices, tmp);
+ break;
+ case SND_MIXER_ETYPE_ACCU3:
+ if (celement->element.data.accu3.voices != uelement->element.data.accu3.voices) {
+ error("Element %s has got a wrong count of voices.", element_id(&celement->element.eid, cardno, devno, id));
+ return 1;
+ }
+ tmp = celement->element.data.accu3.voices * sizeof(int);
+ memcpy(celement->element.data.accu3.pvoices, uelement->element.data.accu3.pvoices, tmp);
+ break;
+ case SND_MIXER_ETYPE_MUX1:
+ if (celement->element.data.mux1.poutput)
+ free(celement->element.data.mux1.poutput);
+ celement->element.data.mux1.output_size = 0;
+ celement->element.data.mux1.output = 0;
+ celement->element.data.mux1.output_over = 0;
+ tmp = uelement->element.data.mux1.output * sizeof(snd_mixer_eid_t);
+ if (tmp > 0) {
+ celement->element.data.mux1.poutput = (snd_mixer_eid_t *)malloc(uelement->element.data.mux1.output_size * sizeof(snd_mixer_eid_t));
+ if (!celement->element.data.mux1.poutput) {
+ error("No enough memory...");
+ return 1;
+ }
+ celement->element.data.mux1.output_size = uelement->element.data.mux1.output_size;
+ celement->element.data.mux1.output = uelement->element.data.mux1.output;
+ memcpy(celement->element.data.mux1.poutput, uelement->element.data.mux1.poutput, tmp);
+ }
+ break;
+ case SND_MIXER_ETYPE_MUX2:
+ celement->element.data.mux2.output = uelement->element.data.mux2.output;
+ 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;
+ 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 = rmixer->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;
+}
+
+static int soundcard_open_ctl(void **ctlhandle, struct soundcard *soundcard)
+{
+ int err;
+
+ if (*ctlhandle)
+ return 0;
+ if ((err = snd_ctl_open(ctlhandle, soundcard->no)) < 0) {
+ error("Cannot open control interface for soundcard #%i.", soundcard->no + 1);
+ return 1;
+ }
+ return 0;
+}
+
+static int soundcard_open_mix(void **mixhandle, struct soundcard *soundcard, struct mixer *mixer)
+{
+ int err;
+
+ if (*mixhandle)
+ return 0;
+ if ((err = snd_mixer_open(mixhandle, soundcard->no, mixer->no)) < 0) {
+ error("Cannot open mixer interface for soundcard #%i.", soundcard->no + 1);
+ return 1;
+ }
+ return 0;
+}
+
+int soundcard_setup_process_switches(int cardno)
+{
+ int err;
+ void *ctlhandle = NULL;
+ struct soundcard *soundcard;
+ struct ctl_switch *ctlsw;
+ struct mixer *mixer;
+ struct pcm *pcm;
+ struct rawmidi *rawmidi;
+
+ for (soundcard = soundcards; soundcard; soundcard = soundcard->next) {
+ if (cardno >= 0 && soundcard->no != cardno)
+ continue;
+ for (ctlsw = soundcard->control.switches; ctlsw; ctlsw = ctlsw->next) {
+ if (ctlsw->change)
+ if (!soundcard_open_ctl(&ctlhandle, soundcard)) {
+ if ((err = snd_ctl_switch_write(ctlhandle, &ctlsw->s)) < 0)
+ error("Control switch '%s' write error: %s", ctlsw->s.name, snd_strerror(err));
+ }
+ }
+ 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_mixer_switch_write(ctlhandle, mixer->no, &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_pcm_playback_switch_write(ctlhandle, pcm->no, &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_pcm_record_switch_write(ctlhandle, pcm->no, &ctlsw->s)) < 0)
+ error("PCM record 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_rawmidi_output_switch_write(ctlhandle, rawmidi->no, &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_rawmidi_output_switch_write(ctlhandle, rawmidi->no, &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;
+ void *ctlhandle = NULL;
+ void *mixhandle = NULL;
+ struct soundcard *soundcard;
+ struct mixer *mixer;
+ struct mixer_element *element;
+
+ for (soundcard = soundcards; soundcard; soundcard = soundcard->next) {
+ if (cardno >= 0 && soundcard->no != cardno)
+ continue;
+ for (mixer = soundcard->mixers; mixer; mixer = mixer->next) {
+ for (element = mixer->elements; element; element = element->next)
+ if (snd_mixer_element_has_control(&element->element.eid) == 1) {
+ if (!soundcard_open_mix(&mixhandle, soundcard, mixer)) {
+ if ((err = snd_mixer_element_write(mixhandle, &element->element)) < 0)
+ error("Mixer element %s write error: %s", mixer_element_id(&element->element.eid), snd_strerror(err));
+ }
+ }
+ if (mixhandle) {
+ snd_mixer_close(mixhandle);
+ mixhandle = NULL;
+ }
+ }
+ if(ctlhandle) {
+ snd_ctl_close(ctlhandle);
+ ctlhandle = NULL;
+ }
+ }
+ return 0;
+}
extern FILE *yyin;
extern int yydebug;
struct soundcard *soundcards = NULL;
+struct soundcard *rsoundcards = NULL;
+
+/*
+ * misc functions
+ */
+
+static char *mixer_element_name(snd_mixer_eid_t *eid)
+{
+ static char str[32];
+
+ if (!eid)
+ return "???";
+ strncpy(str, eid->name, sizeof(eid->name));
+ str[sizeof(eid->name)] = '\0';
+ return str;
+}
+
+char *mixer_element_id(snd_mixer_eid_t *eid)
+{
+ static char str[64];
+
+ if (!eid)
+ return "???";
+ sprintf(str, "%s:%i:%i", mixer_element_name(eid), eid->index, eid->type);
+ return str;
+}
/*
* free functions
}
}
-static void soundcard_mixer_channel_free(struct mixer_channel *first)
+static void soundcard_mixer_element_free(struct mixer_element *first)
{
- struct mixer_channel *next;
+ 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;
}
{
if (!mixer)
return;
- soundcard_mixer_channel_free(mixer->channels);
+ soundcard_mixer_element_free(mixer->elements);
soundcard_ctl_switch_free(mixer->switches);
free(mixer);
}
void soundcard_setup_done(void)
{
soundcard_free(soundcards);
+ soundcard_free(rsoundcards);
soundcards = NULL;
}
return 0;
}
-int soundcard_setup_collect(int cardno)
+static int soundcard_setup_collect_switches1(int cardno)
{
void *handle, *mhandle;
struct soundcard *card, *first, *prev;
- int err, idx, count, device;
+ int err, device;
struct mixer *mixer, *mixerprev;
- struct mixer_channel *mixerchannel, *mixerchannelprev;
struct pcm *pcm, *pcmprev;
struct rawmidi *rawmidi, *rawmidiprev;
mixerprev = mixer;
if ((err = snd_mixer_open(&mhandle, cardno, device)) < 0) {
snd_ctl_close(handle);
- error("MIXER open error: %s\n", snd_strerror(err));
- return 1;
- }
- if ((err = snd_mixer_exact_mode(mhandle, 1)) < 0) {
- snd_mixer_close(mhandle);
- snd_ctl_close(handle);
- error("MIXER exact mode error: %s\n", snd_strerror(err));
+ 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\n", snd_strerror(err));
+ error("MIXER info error: %s", snd_strerror(err));
return 1;
}
- count = snd_mixer_channels(mhandle);
- for (idx = 0, mixerchannelprev = NULL; idx < count; idx++) {
- mixerchannel = (struct mixer_channel *) malloc(sizeof(struct mixer_channel));
- if (!mixerchannel) {
- snd_mixer_close(mhandle);
- snd_ctl_close(handle);
- error("malloc problem");
- return 1;
- }
- bzero(mixerchannel, sizeof(struct mixer_channel));
- mixerchannel->no = idx;
- if ((err = snd_mixer_channel_info(mhandle, idx, &mixerchannel->info)) < 0) {
- free(mixerchannel);
- error("MIXER channel info error (%s) - skipping", snd_strerror(err));
- break;
- }
- if ((mixerchannel->info.caps & SND_MIXER_CINFO_CAP_OUTPUT) &&
- (err = snd_mixer_channel_output_info(mhandle, idx, &mixerchannel->dinfo[OUTPUT])) < 0) {
- free(mixerchannel);
- error("MIXER channel output info error (%s) - skipping", snd_strerror(err));
- break;
- }
- if ((mixerchannel->info.caps & SND_MIXER_CINFO_CAP_INPUT) &&
- (err = snd_mixer_channel_input_info(mhandle, idx, &mixerchannel->dinfo[INPUT])) < 0) {
- free(mixerchannel);
- error("MIXER channel input info error (%s) - skipping", snd_strerror(err));
- break;
- }
- if ((err = snd_mixer_channel_read(mhandle, idx, &mixerchannel->data)) < 0) {
- free(mixerchannel);
- error("MIXER channel read error (%s) - skipping", snd_strerror(err));
- break;
- }
- if ((mixerchannel->info.caps & SND_MIXER_CINFO_CAP_OUTPUT) &&
- (err = snd_mixer_channel_output_read(mhandle, idx, &mixerchannel->ddata[OUTPUT])) < 0) {
- free(mixerchannel);
- error("MIXER channel output read error (%s) - skipping", snd_strerror(err));
- break;
- }
- if ((mixerchannel->info.caps & SND_MIXER_CINFO_CAP_INPUT) &&
- (err = snd_mixer_channel_input_read(mhandle, idx, &mixerchannel->ddata[INPUT])) < 0) {
- free(mixerchannel);
- error("MIXER channel input read error (%s) - skipping", snd_strerror(err));
- break;
- }
- if (!mixerchannelprev) {
- mixer->channels = mixerchannel;
- } else {
- mixerchannelprev->next = mixerchannel;
- }
- mixerchannelprev = mixerchannel;
- }
snd_mixer_close(mhandle);
}
/* --- */
pcm->no = device;
if ((err = snd_ctl_pcm_info(handle, device, &pcm->info)) < 0) {
snd_ctl_close(handle);
- error("PCM info error: %s\n", snd_strerror(err));
+ error("PCM info error: %s", snd_strerror(err));
return 1;
}
if (determine_switches(handle, &pcm->pswitches, 2, device)) {
rawmidi->no = device;
if ((err = snd_ctl_rawmidi_info(handle, device, &rawmidi->info)) < 0) {
snd_ctl_close(handle);
- error("RAWMIDI info error: %s\n", snd_strerror(err));
+ error("RAWMIDI info error: %s", snd_strerror(err));
return 1;
}
if (determine_switches(handle, &rawmidi->oswitches, 4, device)) {
return 0;
}
+int soundcard_setup_collect_switches(int cardno)
+{
+ int err;
+ unsigned int mask;
+
+ if (cardno >= 0) {
+ return soundcard_setup_collect_switches1(cardno);
+ } else {
+ mask = snd_cards_mask();
+ for (cardno = 0; cardno < SND_CARDS; cardno++) {
+ if (!(mask & (1 << cardno)))
+ continue;
+ err = soundcard_setup_collect_switches1(cardno);
+ if (err)
+ return err;
+ }
+ return 0;
+ }
+}
+
+static int soundcard_setup_collect_data1(int cardno)
+{
+ void *handle, *mhandle;
+ struct soundcard *card;
+ int err, idx;
+ struct mixer *mixer;
+ snd_mixer_elements_t elements;
+ struct mixer_element *mixerelement, *mixerelementprev;
+
+ if ((err = snd_ctl_open(&handle, cardno)) < 0) {
+ error("SND CTL open error: %s", snd_strerror(err));
+ return 1;
+ }
+ /* --- */
+ for (card = soundcards; card && card->no != cardno; card = card->next);
+ if (!card) {
+ snd_ctl_close(handle);
+ error("The soundcard %i does not exist.", cardno);
+ return 1;
+ }
+ for (mixer = card->mixers; mixer; mixer = mixer->next) {
+ if ((err = snd_mixer_open(&mhandle, cardno, mixer->no)) < 0) {
+ snd_ctl_close(handle);
+ error("MIXER open error: %s", snd_strerror(err));
+ return 1;
+ }
+ if (mixer->elements)
+ soundcard_mixer_element_free(mixer->elements);
+ mixer->elements = NULL;
+ bzero(&elements, sizeof(elements));
+ if ((err = snd_mixer_elements(mhandle, &elements)) < 0) {
+ snd_mixer_close(mhandle);
+ snd_ctl_close(handle);
+ error("MIXER elements error: %s", snd_strerror(err));
+ return 1;
+ }
+ elements.elements_size = elements.elements_over + 16;
+ elements.elements = elements.elements_over = 0;
+ elements.pelements = (snd_mixer_eid_t *)malloc(elements.elements_size * sizeof(snd_mixer_eid_t));
+ if ((err = snd_mixer_elements(mhandle, &elements)) < 0) {
+ snd_mixer_close(mhandle);
+ snd_ctl_close(handle);
+ error("MIXER elements (2) error: %s", snd_strerror(err));
+ return 1;
+ }
+ for (idx = 0, mixerelementprev = NULL; idx < elements.elements; idx++) {
+ mixerelement = (struct mixer_element *) malloc(sizeof(struct mixer_element));
+ if (!mixerelement) {
+ snd_mixer_close(mhandle);
+ snd_ctl_close(handle);
+ error("malloc problem");
+ return 1;
+ }
+ bzero(mixerelement, sizeof(*mixerelement));
+ mixerelement->info.eid = elements.pelements[idx];
+ mixerelement->element.eid = elements.pelements[idx];
+ if (snd_mixer_element_has_info(&elements.pelements[idx]) == 1) {
+ if ((err = snd_mixer_element_info_build(mhandle, &mixerelement->info)) < 0) {
+ free(mixerelement);
+ error("MIXER element %s info error (%s) - skipping", mixer_element_id(&mixerelement->info.eid), snd_strerror(err));
+ break;
+ }
+ }
+ if (snd_mixer_element_has_control(&elements.pelements[idx]) == 1) {
+ if ((err = snd_mixer_element_build(mhandle, &mixerelement->element)) < 0) {
+ free(mixerelement);
+ error("MIXER element %s build error (%s) - skipping", mixer_element_id(&mixerelement->element.eid), snd_strerror(err));
+ break;
+ }
+ }
+ if (!mixerelementprev) {
+ mixer->elements = mixerelement;
+ } else {
+ mixerelementprev->next = mixerelement;
+ }
+ mixerelementprev = mixerelement;
+ }
+ free(elements.pelements);
+ snd_mixer_close(mhandle);
+ }
+ /* --- */
+ snd_ctl_close(handle);
+ return 0;
+}
+
+int soundcard_setup_collect_data(int cardno)
+{
+ int err;
+ unsigned int mask;
+
+ if (cardno >= 0) {
+ return soundcard_setup_collect_data1(cardno);
+ } else {
+ mask = snd_cards_mask();
+ for (cardno = 0; cardno < SND_CARDS; cardno++) {
+ if (!(mask & (1 << cardno)))
+ continue;
+ err = soundcard_setup_collect_data1(cardno);
+ if (err)
+ return err;
+ }
+ return 0;
+ }
+}
+
+
+
int soundcard_setup_load(const char *cfgfile, int skip)
{
extern int yyparse(void);
default:
s = "unknown";
}
- fprintf(out, "%s; Type is '%s'.\n", space, s);
+ fprintf(out, "%s; The type is '%s'.\n", space, s);
if (sw->low != 0 || sw->high != 0)
- fprintf(out, "%s; Accepted switch range is from %u to %u.\n", space, sw->low, sw->high);
+ fprintf(out, "%s; The accepted switch range is from %u to %u.\n", space, sw->low, sw->high);
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++) {
fprintf(out, "\n");
}
if (interface == SND_INTERFACE_MIXER && sw->type == SND_SW_TYPE_BOOLEAN &&
- !strcmp(sw->name, SND_MIXER_SW_IEC958OUT)) {
- fprintf(out, "%sswitch( \"%s\", ", space, sw->name);
+ !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");
+ fprintf(out, "iec958ocs(%s", sw->value.enable ? "enable" : "disable");
if (sw->value.data16[4] & 0x2000)
- fprintf(out, " 3d");
+ fprintf(out, ",3d");
if (sw->value.data16[4] & 0x0040)
- fprintf(out, " reset");
+ fprintf(out, ",reset");
if (sw->value.data16[4] & 0x0020)
- fprintf(out, " user");
+ fprintf(out, ",user");
if (sw->value.data16[4] & 0x0010)
- fprintf(out, " valid");
+ fprintf(out, ",valid");
if (sw->value.data16[5] & 0x0002)
- fprintf(out, " data");
+ fprintf(out, ",data");
if (!(sw->value.data16[5] & 0x0004))
- fprintf(out, " protect");
+ fprintf(out, ",protect");
switch (sw->value.data16[5] & 0x0018) {
case 0x0008:
- fprintf(out, " pre2");
+ fprintf(out, ",pre2");
break;
default:
break;
}
if (sw->value.data16[5] & 0x0020)
- fprintf(out, " fsunlock");
- fprintf(out, " type( 0x%x )", (sw->value.data16[5] >> 6) & 0x7f);
+ fprintf(out, ",fsunlock");
+ fprintf(out, ",type(0x%x)", (sw->value.data16[5] >> 6) & 0x7f);
if (sw->value.data16[5] & 0x2000)
- fprintf(out, " gstatus");
- fprintf(out, " )");
+ fprintf(out, ",gstatus");
+ fprintf(out, ")");
goto __end;
}
}
fprintf(out, v);
if (sw->type < 0 || sw->type > SND_SW_TYPE_LIST_ITEM) {
/* TODO: some well known types should be verbose */
- fprintf(out, " rawdata( ");
+ fprintf(out, "rawdata(");
for (idx = 0; idx < 31; idx++) {
fprintf(out, "@%02x:", sw->value.data8[idx]);
}
- fprintf(out, "%02x@ )\n", sw->value.data8[31]);
+ fprintf(out, "%02x@)\n", sw->value.data8[31]);
}
}
__end:
- fprintf(out, " )\n");
+ fprintf(out, ")\n");
}
static void soundcard_setup_write_switches(FILE *out, const char *space, int interface, struct ctl_switch **switches)
soundcard_setup_write_switch(out, space, interface, &sw->s);
}
-static void soundcard_setup_write_mixer_channel(FILE * out, struct mixer_channel * channel)
+static void soundcard_setup_write_mixer_element(FILE * out, struct mixer_element * xelement)
{
- int k, d;
- struct capdes {
- unsigned int flag;
- char* description;
- };
- static struct capdes caps[] = {
- { SND_MIXER_CINFO_CAP_OUTPUT, "output" },
- { SND_MIXER_CINFO_CAP_INPUT, "input" },
- { SND_MIXER_CINFO_CAP_EXTINPUT, "external-input" },
- { SND_MIXER_CINFO_CAP_EFFECT, "effect" }
- };
- static struct capdes dcaps[] = {
- { SND_MIXER_CINFO_DCAP_STEREO, "stereo" },
- { SND_MIXER_CINFO_DCAP_HWMUTE, "hardware-mute" },
- { SND_MIXER_CINFO_DCAP_JOINMUTE, "join-mute" },
- { SND_MIXER_CINFO_DCAP_ROUTE, "route" },
- { SND_MIXER_CINFO_DCAP_SWAPROUTE, "swap-route" },
- { SND_MIXER_CINFO_DCAP_DIGITAL, "digital" },
- { SND_MIXER_CINFO_DCAP_RECORDBYMUTE, "recordbymute" },
- };
-
- fprintf(out, " ; Capabilities:");
- for (k = 0; k < sizeof(caps)/sizeof(*caps); ++k) {
- if (channel->info.caps & caps[k].flag)
- fprintf(out, " %s", caps[k].description);
+ 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, " ; Voice %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.voices; idx++)
+ fprintf(out, "%s%i", idx > 0 ? "," : "", element->data.volume1.pvoices[idx]);
+ fprintf(out, "))\n");
+ break;
+ case SND_MIXER_ETYPE_ACCU3:
+ for (idx = 0; idx < info->data.accu3.range; idx++)
+ fprintf(out, " ; Voice %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.voices; idx++)
+ fprintf(out, "%s%i", idx > 0 ? "," : "", element->data.accu3.pvoices[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.output; idx++) {
+ fprintf(out, "%selement(\"%s\",%i,%i)", idx > 0 ? "," : "", mixer_element_name(&element->data.mux1.poutput[idx]), element->data.mux1.poutput[idx].index, element->data.mux1.poutput[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.output), element->data.mux2.output.index, element->data.mux2.output.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);
+ 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);
+ fprintf(out, "))\n");
+ break;
+ default:
+ fprintf(out, " ; Unknown element %s\n", mixer_element_id(&element->eid));
}
- fprintf(out, "\n");
- for (d = OUTPUT; d <= INPUT; ++d) {
- snd_mixer_channel_direction_info_t *di;
- if (d == OUTPUT &&
- !(channel->info.caps & SND_MIXER_CINFO_CAP_OUTPUT))
- continue;
- if (d == INPUT &&
- !(channel->info.caps & SND_MIXER_CINFO_CAP_INPUT))
- continue;
- di = &channel->dinfo[d];
- fprintf(out, " ; %s capabilities:",
- d == OUTPUT ? "Output" : "Input" );
- if (di->caps & SND_MIXER_CINFO_DCAP_VOLUME)
- fprintf(out, " volume(%i, %i)", di->min, di->max);
- for (k = 0; k < sizeof(caps)/sizeof(*caps); ++k) {
- if (di->caps & dcaps[k].flag)
- fprintf(out, " %s", dcaps[k].description);
- }
- fprintf(out, "\n");
- }
- fprintf(out, " channel(\"%s\"", channel->info.name);
- for (d = OUTPUT; d <= INPUT; ++d) {
- snd_mixer_channel_direction_info_t *di;
- snd_mixer_channel_direction_t *dd;
- if (d == OUTPUT &&
- !(channel->info.caps & SND_MIXER_CINFO_CAP_OUTPUT))
- continue;
- if (d == INPUT &&
- !(channel->info.caps & SND_MIXER_CINFO_CAP_INPUT))
- continue;
- dd = &channel->ddata[d];
- di = &channel->dinfo[d];
- fprintf(out, ", %s ", d == OUTPUT ? "output" : "input" );
- if (di->caps & SND_MIXER_CINFO_DCAP_STEREO) {
- fprintf(out, "stereo(");
- if (di->caps & SND_MIXER_CINFO_DCAP_VOLUME)
- fprintf(out, " %i", dd->left);
- fprintf(out, "%s%s,",
- dd->flags & SND_MIXER_DFLG_MUTE_LEFT ? " mute" : "",
- dd->flags & SND_MIXER_DFLG_LTOR ? " swap" : ""
- );
- if (di->caps & SND_MIXER_CINFO_DCAP_VOLUME)
- fprintf(out, " %i", dd->right);
-
- fprintf(out, "%s%s)",
- dd->flags & SND_MIXER_DFLG_MUTE_RIGHT ? " mute" : "",
- dd->flags & SND_MIXER_DFLG_RTOL ? " swap" : ""
- );
- }
- else {
- fprintf(out, "mono(");
- if (di->caps & SND_MIXER_CINFO_DCAP_VOLUME)
- fprintf(out, " %i", (dd->left + dd->right)/2);
- fprintf(out, "%s)",
- dd->flags & SND_MIXER_DFLG_MUTE ? " mute" : ""
- );
- }
- }
- fprintf(out, " )\n");
}
-int soundcard_setup_write(const char *cfgfile)
+#define MAX_LINE (32 * 1024)
+
+int soundcard_setup_write(const char *cfgfile, int cardno)
{
- FILE *out;
- struct soundcard *first;
+ FILE *out, *out1, *out2, *in;
+ char *tmpfile1, *tmpfile2;
+ struct soundcard *first, *sel = NULL;
struct mixer *mixer;
- struct mixer_channel *mixerchannel;
+ struct mixer_element *mixerelement;
struct pcm *pcm;
struct rawmidi *rawmidi;
+ char *line, cardname[sizeof(first->control.hwinfo.name)+16], *ptr1;
+ int mark, size, ok;
- if ((out = fopen(cfgfile, "w+")) == NULL) {
- error("Cannot open file '%s' for writing...\n", cfgfile);
+ tmpfile1 = (char *)malloc(strlen(cfgfile) + 16);
+ tmpfile2 = (char *)malloc(strlen(cfgfile) + 16);
+ if (!tmpfile1 || !tmpfile2) {
+ error("No enough memory...\n");
+ if (tmpfile1)
+ free(tmpfile1);
+ if (tmpfile2)
+ free(tmpfile2);
+ return 1;
+ }
+ strcpy(tmpfile1, cfgfile);
+ strcat(tmpfile1, ".new");
+ strcpy(tmpfile2, cfgfile);
+ strcat(tmpfile2, ".insert");
+
+ if (cardno >= 0) {
+ line = (char *)malloc(MAX_LINE);
+ if (!line) {
+ error("No enough memory...\n");
+ return 1;
+ }
+ if ((in = fopen(cfgfile, "r")) == NULL)
+ cardno = -1;
+ } else {
+ line = NULL;
+ in = NULL;
+ }
+ if ((out = out1 = fopen(tmpfile1, "w+")) == NULL) {
+ error("Cannot open file '%s' for writing...\n", tmpfile1);
return 1;
}
fprintf(out, "# ALSA driver configuration\n");
- fprintf(out, "# Generated by alsactl\n");
+ fprintf(out, "# This configuration is generated with the alsactl program.\n");
fprintf(out, "\n");
+ if (cardno >= 0) {
+ if ((out = out2 = fopen(tmpfile2, "w+")) == NULL) {
+ error("Cannot open file '%s' for writing...\n", tmpfile2);
+ return 1;
+ }
+ } else {
+ out2 = NULL;
+ }
for (first = soundcards; first; first = first->next) {
+ if (cardno >= 0 && first->no != cardno)
+ continue;
+ sel = first;
fprintf(out, "soundcard(\"%s\") {\n", first->control.hwinfo.id);
if (first->control.switches) {
fprintf(out, " control {\n");
for (mixer = first->mixers; mixer; mixer = mixer->next) {
fprintf(out, " mixer(\"%s\") {\n", mixer->info.name);
soundcard_setup_write_switches(out, " ", SND_INTERFACE_MIXER, &mixer->switches);
- for (mixerchannel = mixer->channels; mixerchannel; mixerchannel = mixerchannel->next)
- soundcard_setup_write_mixer_channel(out, mixerchannel);
+ 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) {
}
fprintf(out, " }\n");
}
- fprintf(out, "}\n%s", first->next ? "\n" : "");
- }
- fclose(out);
- return 0;
-}
-
-static int soundcard_open_ctl(void **ctlhandle, struct soundcard *soundcard)
-{
- int err;
-
- if (*ctlhandle)
- return 0;
- if ((err = snd_ctl_open(ctlhandle, soundcard->no)) < 0) {
- error("Cannot open control interface for soundcard #%i.", soundcard->no + 1);
- return 1;
+ fprintf(out, "}\n%s", cardno < 0 && first->next ? "\n" : "");
}
- return 0;
-}
-
-static int soundcard_open_mix(void **mixhandle, struct soundcard *soundcard, struct mixer *mixer)
-{
- int err;
-
- if (*mixhandle)
- return 0;
- if ((err = snd_mixer_open(mixhandle, soundcard->no, mixer->no)) < 0) {
- error("Cannot open mixer interface for soundcard #%i.", soundcard->no + 1);
- return 1;
- }
- if ((err = snd_mixer_exact_mode(*mixhandle, 1)) < 0) {
- error("Cannot setup exact mode for mixer #%i/#%i: %s", soundcard->no + 1, mixer->no, snd_strerror(err));
- return 1;
- }
- return 0;
-}
-
-int soundcard_setup_process(int cardno)
-{
- int err;
- void *ctlhandle = NULL;
- void *mixhandle = NULL;
- struct soundcard *soundcard;
- struct ctl_switch *ctlsw;
- struct mixer *mixer;
- struct mixer_channel *channel;
- struct pcm *pcm;
- struct rawmidi *rawmidi;
-
- for (soundcard = soundcards; soundcard; soundcard = soundcard->next) {
- if (cardno >= 0 && soundcard->no != cardno)
- continue;
- for (ctlsw = soundcard->control.switches; ctlsw; ctlsw = ctlsw->next) {
- if (ctlsw->change)
- if (!soundcard_open_ctl(&ctlhandle, soundcard)) {
- if ((err = snd_ctl_switch_write(ctlhandle, &ctlsw->s)) < 0)
- error("Control switch '%s' write error: %s", ctlsw->s.name, snd_strerror(err));
- }
- }
- for (mixer = soundcard->mixers; mixer; mixer = mixer->next) {
- for (channel = mixer->channels; channel; channel = channel->next)
- if (!soundcard_open_mix(&mixhandle, soundcard, mixer)) {
- if ((channel->info.caps & SND_MIXER_CINFO_CAP_OUTPUT) &&
- (err = snd_mixer_channel_output_write(mixhandle, channel->no, &channel->ddata[OUTPUT])) < 0)
- error("Mixer channel '%s' write error: %s", channel->info.name, snd_strerror(err));
- if ((channel->info.caps & SND_MIXER_CINFO_CAP_INPUT) &&
- (err = snd_mixer_channel_input_write(mixhandle, channel->no, &channel->ddata[INPUT])) < 0)
- error("Mixer channel '%s' record write error: %s", channel->info.name, snd_strerror(err));
- }
- if (mixhandle) {
- snd_mixer_close(mixhandle);
- mixhandle = NULL;
- }
- for (ctlsw = mixer->switches; ctlsw; ctlsw = ctlsw->next)
- if (ctlsw->change)
- if (!soundcard_open_ctl(&ctlhandle, soundcard)) {
- if ((err = snd_ctl_mixer_switch_write(ctlhandle, mixer->no, &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_pcm_playback_switch_write(ctlhandle, pcm->no, &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_pcm_record_switch_write(ctlhandle, pcm->no, &ctlsw->s)) < 0)
- error("PCM record switch '%s' write error: %s", ctlsw->s.name, snd_strerror(err));
- }
- }
+ /* merge the old and new text */
+ if (cardno >= 0) {
+ fseek(out2, 0, SEEK_SET);
+ mark = ok = 0;
+ __1:
+ while (fgets(line, MAX_LINE - 1, in)) {
+ line[MAX_LINE - 1] = '\0';
+ if (!strncmp(line, "soundcard(", 10))
+ break;
}
- 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_rawmidi_output_switch_write(ctlhandle, rawmidi->no, &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_rawmidi_output_switch_write(ctlhandle, rawmidi->no, &ctlsw->s)) < 0)
- error("RAWMIDI input switch '%s' write error: %s", ctlsw->s.name, snd_strerror(err));
+ while (!feof(in)) {
+ ptr1 = line + 10;
+ while (*ptr1 && *ptr1 != '"')
+ ptr1++;
+ if (*ptr1)
+ ptr1++;
+ strncpy(cardname, sel->control.hwinfo.id, sizeof(sel->control.hwinfo.id));
+ cardname[sizeof(sel->control.hwinfo.id)] = '\0';
+ strcat(cardname, "\"");
+ if (!strncmp(ptr1, cardname, strlen(cardname))) {
+ if (mark)
+ fprintf(out1, "\n");
+ do {
+ size = fread(line, 1, MAX_LINE, out2);
+ if (size > 0)
+ fwrite(line, 1, size, out1);
+ } while (size > 0);
+ mark = ok = 1;
+ goto __1;
+ } else {
+ if (mark)
+ fprintf(out1, "\n");
+ fprintf(out1, line);
+ while (fgets(line, MAX_LINE - 1, in)) {
+ line[MAX_LINE - 1] = '\0';
+ fprintf(out1, line);
+ if (line[0] == '}') {
+ mark = 1;
+ goto __1;
}
+ }
}
}
- if(ctlhandle) {
- snd_ctl_close(ctlhandle);
- ctlhandle = NULL;
+ if (!ok) {
+ if (mark)
+ fprintf(out1, "\n");
+ do {
+ size = fread(line, 1, MAX_LINE, out2);
+ printf("size = %i\n", size);
+ if (size > 0)
+ fwrite(line, 1, size, out1);
+ } while (size > 0);
}
}
+ if (in)
+ fclose(in);
+ if (out2)
+ fclose(out2);
+ if (!access(cfgfile, F_OK) && remove(cfgfile))
+ error("Cannot remove file '%s'...", cfgfile);
+ if (rename(tmpfile1, cfgfile) < 0)
+ error("Cannot rename file '%s' to '%s'...", tmpfile1, cfgfile);
+ fclose(out1);
+ if (line)
+ free(line);
+ if (tmpfile2) {
+ remove(tmpfile2);
+ free(tmpfile2);
+ }
+ if (tmpfile1) {
+ remove(tmpfile1);
+ free(tmpfile1);
+ }
return 0;
}
-/* AlsaMixer - Commandline mixer for the ALSA project
- * Copyright (C) 1998 Jaroslav Kysela <perex@jcu.cz>,
- * Tim Janik <timj@gtk.org>,
- * Carl van Schaik <carl@dreamcoat.che.uct.ac.za>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
- */
-
#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-
-#include <errno.h>
-
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/signal.h>
-
-#ifndef CURSESINC
-#include <ncurses.h>
-#else
-#include CURSESINC
-#endif
-#include <time.h>
-
-#include <sys/asoundlib.h>
-
-/* example compilation commandline:
- * clear; gcc -Wall -pipe -O2 alsamixer.c -o alsamixer -lncurses
- */
-
-/* --- defines --- */
-#define PRGNAME "alsamixer"
-#define PRGNAME_UPPER "AlsaMixer"
-#define VERSION "v0.9"
-
-#undef MAX
-#define MAX(a, b) (((a) > (b)) ? (a) : (b))
-#undef MIN
-#define MIN(a, b) (((a) < (b)) ? (a) : (b))
-#undef ABS
-#define ABS(a) (((a) < 0) ? -(a) : (a))
-#undef CLAMP
-#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
-
-#define MIXER_MIN_X (23) /* minimum: 23 */
-#define MIXER_MIN_Y (19) /* minimum: 19 */
-
-#define MIXER_BLACK (COLOR_BLACK)
-#define MIXER_DARK_RED (COLOR_RED)
-#define MIXER_RED (COLOR_RED | A_BOLD)
-#define MIXER_GREEN (COLOR_GREEN | A_BOLD)
-#define MIXER_ORANGE (COLOR_YELLOW)
-#define MIXER_YELLOW (COLOR_YELLOW | A_BOLD)
-#define MIXER_MARIN (COLOR_BLUE)
-#define MIXER_BLUE (COLOR_BLUE | A_BOLD)
-#define MIXER_MAGENTA (COLOR_MAGENTA)
-#define MIXER_DARK_CYAN (COLOR_CYAN)
-#define MIXER_CYAN (COLOR_CYAN | A_BOLD)
-#define MIXER_GREY (COLOR_WHITE)
-#define MIXER_GRAY (MIXER_GREY)
-#define MIXER_WHITE (COLOR_WHITE | A_BOLD)
-
-
-/* --- variables --- */
-static WINDOW *mixer_window = NULL;
-static int mixer_max_x = 0;
-static int mixer_max_y = 0;
-static int mixer_ofs_x = 0;
-static float mixer_extra_space = 0;
-static int mixer_ofs_y = 0;
-static int mixer_cbar_height = 0;
-
-static int card_id = 0;
-static int mixer_id = 0;
-static void *mixer_handle;
-static char *mixer_card_name = NULL;
-static char *mixer_device_name = NULL;
-
-static int mixer_n_channels = 0;
-static int mixer_n_vis_channels = 0;
-static int mixer_first_vis_channel = 0;
-static int mixer_focus_channel = 0;
-static int mixer_exact = 0;
-
-static int mixer_input_volumes = 0;
-
-static int mixer_lvolume_delta = 0;
-static int mixer_rvolume_delta = 0;
-static int mixer_balance_volumes = 0;
-static int mixer_toggle_mute_left = 0;
-static int mixer_toggle_mute_right = 0;
-
-/* By Carl */
-static int mixer_toggle_record_left = 0;
-static int mixer_toggle_record_right = 0;
-static int mixer_route_ltor_in = 0;
-static int mixer_route_rtol_in = 0;
-#if 0
-static int mixer_route_ltor_out = 0;
-static int mixer_route_rtol_out = 0;
-#endif
-
-
-/* --- draw contexts --- */
-enum {
- DC_DEFAULT,
- DC_BACK,
- DC_TEXT,
- DC_PROMPT,
- DC_CBAR_MUTE,
- DC_CBAR_NOMUTE,
- DC_CBAR_RECORD,
- DC_CBAR_NORECORD,
- DC_CBAR_EMPTY,
- DC_CBAR_FULL_1,
- DC_CBAR_FULL_2,
- DC_CBAR_FULL_3,
- DC_CBAR_LABEL,
- DC_CBAR_FOCUS_LABEL,
- DC_FOCUS,
- DC_LAST
-};
-
-static int dc_fg[DC_LAST] =
-{0};
-static int dc_attrib[DC_LAST] =
-{0};
-static int dc_char[DC_LAST] =
-{0};
-static int mixer_do_color = 1;
-
-static void mixer_init_dc(int c,
- int n,
- int f,
- int b,
- int a)
-{
- dc_fg[n] = f;
- dc_attrib[n] = a;
- dc_char[n] = c;
- if (n > 0)
- init_pair(n, dc_fg[n] & 0xf, b & 0x0f);
-}
-
-static int mixer_dc(int n)
-{
- if (mixer_do_color)
- attrset(COLOR_PAIR(n) | (dc_fg[n] & 0xfffffff0));
- else
- attrset(dc_attrib[n]);
-
- return dc_char[n];
-}
-
-static void mixer_init_draw_contexts(void)
-{
- start_color();
-
- mixer_init_dc('.', DC_BACK, MIXER_WHITE, MIXER_BLACK, A_NORMAL);
- mixer_init_dc('.', DC_TEXT, MIXER_YELLOW, MIXER_BLACK, A_BOLD);
- mixer_init_dc('.', DC_PROMPT, MIXER_DARK_CYAN, MIXER_BLACK, A_NORMAL);
- mixer_init_dc('M', DC_CBAR_MUTE, MIXER_CYAN, MIXER_BLACK, A_BOLD);
- mixer_init_dc('-', DC_CBAR_NOMUTE, MIXER_CYAN, MIXER_BLACK, A_NORMAL);
- mixer_init_dc('x', DC_CBAR_RECORD, MIXER_DARK_RED, MIXER_BLACK, A_BOLD);
- mixer_init_dc('-', DC_CBAR_NORECORD, MIXER_GRAY, MIXER_BLACK, A_NORMAL);
- mixer_init_dc(' ', DC_CBAR_EMPTY, MIXER_GRAY, MIXER_BLACK, A_DIM);
- mixer_init_dc('#', DC_CBAR_FULL_1, MIXER_WHITE, MIXER_BLACK, A_BOLD);
- mixer_init_dc('#', DC_CBAR_FULL_2, MIXER_GREEN, MIXER_BLACK, A_BOLD);
- mixer_init_dc('#', DC_CBAR_FULL_3, MIXER_RED, MIXER_BLACK, A_BOLD);
- mixer_init_dc('.', DC_CBAR_LABEL, MIXER_WHITE, MIXER_BLUE, A_REVERSE | A_BOLD);
- mixer_init_dc('.', DC_CBAR_FOCUS_LABEL, MIXER_RED, MIXER_BLUE, A_REVERSE | A_BOLD);
- mixer_init_dc('.', DC_FOCUS, MIXER_RED, MIXER_BLACK, A_BOLD);
-}
-
-#define DC_CBAR_FRAME (DC_CBAR_MUTE)
-#define DC_FRAME (DC_PROMPT)
-
-
-/* --- error types --- */
-typedef enum {
- ERR_NONE,
- ERR_OPEN,
- ERR_FCN,
- ERR_SIGNAL,
- ERR_WINSIZE,
-} ErrType;
-
-
-/* --- prototypes --- */
-static void mixer_abort(ErrType error,
- const char *err_string)
- __attribute__
- ((noreturn));
-
-
-/* --- functions --- */
-static void mixer_clear(void)
-{
- int x, y;
-
- mixer_dc(DC_BACK);
- clear();
-
- /* buggy ncurses doesn't really write spaces with the specified
- * color into the screen on clear ();
- */
- for (x = 0; x < mixer_max_x; x++)
- for (y = 0; y < mixer_max_y; y++)
- mvaddch(y, x, ' ');
- refresh();
-}
-
-static void mixer_abort(ErrType error,
- const char *err_string)
-{
- if (mixer_window) {
- mixer_clear();
- endwin();
- mixer_window = NULL;
- }
- printf("\n");
-
- switch (error) {
- case ERR_OPEN:
- fprintf(stderr,
- PRGNAME ": failed to open mixer #%i/#%i: %s\n",
- card_id,
- mixer_id,
- snd_strerror(errno));
- break;
- case ERR_FCN:
- fprintf(stderr,
- PRGNAME ": function %s failed: %s\n",
- err_string,
- snd_strerror(errno));
- break;
- case ERR_SIGNAL:
- fprintf(stderr,
- PRGNAME ": aborting due to signal `%s'\n",
- err_string);
- break;
- case ERR_WINSIZE:
- fprintf(stderr,
- PRGNAME ": screen size too small (%dx%d)\n",
- mixer_max_x,
- mixer_max_y);
- break;
- default:
- break;
- }
-
- exit(error);
-}
-
-static int mixer_cbar_get_pos(int channel_index,
- int *x_p,
- int *y_p)
-{
- int x;
- int y;
-
- if (channel_index < mixer_first_vis_channel ||
- channel_index - mixer_first_vis_channel >= mixer_n_vis_channels)
- return FALSE;
-
- channel_index -= mixer_first_vis_channel;
-
- x = mixer_ofs_x + 1;
- y = mixer_ofs_y;
- x += channel_index * (3 + 2 + 3 + 1 + mixer_extra_space);
- y += mixer_max_y / 2;
- y += mixer_cbar_height / 2 + 1;
-
- if (x_p)
- *x_p = x;
- if (y_p)
- *y_p = y;
-
- return TRUE;
-}
-
-static void mixer_update_cbar(int channel_index)
-{
- char string[64];
- char c;
- snd_mixer_channel_info_t cinfo =
- {0};
- snd_mixer_channel_direction_info_t cpinfo =
- {0};
- snd_mixer_channel_direction_info_t crinfo =
- {0};
- snd_mixer_channel_direction_t cpdata =
- {0};
- snd_mixer_channel_direction_t crdata =
- {0};
- int vleft, vright;
- int x, y, i;
- int output = 0, input = 0, volume;
-
- /* set specified EXACT mode
- */
- if (snd_mixer_exact_mode(mixer_handle, mixer_exact) < 0)
- mixer_abort(ERR_FCN, "snd_mixer_exact");
-
- /* set new channel indices and read info
- */
- if (snd_mixer_channel_info(mixer_handle, channel_index, &cinfo) < 0)
- mixer_abort(ERR_FCN, "snd_mixer_channel_info");
- if (cinfo.caps & SND_MIXER_CINFO_CAP_OUTPUT) {
- if (snd_mixer_channel_output_info(mixer_handle, channel_index, &cpinfo) < 0)
- mixer_abort(ERR_FCN, "snd_mixer_channel_output_info");
- output = 1;
- }
- if (cinfo.caps & SND_MIXER_CINFO_CAP_INPUT) {
- if (snd_mixer_channel_input_info(mixer_handle, channel_index, &crinfo) < 0)
- mixer_abort(ERR_FCN, "snd_mixer_channel_input_info");
- input = 1;
- }
- if (mixer_input_volumes)
- volume=(input && (crinfo.caps & SND_MIXER_CINFO_DCAP_VOLUME));
- else
- volume=(output && (cpinfo.caps & SND_MIXER_CINFO_DCAP_VOLUME));
-
- /* set new channel values
- */
- if (channel_index == mixer_focus_channel &&
- (mixer_lvolume_delta || mixer_rvolume_delta ||
- mixer_toggle_mute_left || mixer_toggle_mute_right ||
- mixer_balance_volumes ||
- mixer_toggle_record_left || mixer_toggle_record_right ||
- mixer_route_rtol_in || mixer_route_ltor_in)) {
- if (output && snd_mixer_channel_output_read(mixer_handle, channel_index, &cpdata) < 0)
- mixer_abort(ERR_FCN, "snd_mixer_channel_output_read");
- if (input && snd_mixer_channel_input_read(mixer_handle, channel_index, &crdata) < 0)
- mixer_abort(ERR_FCN, "snd_mixer_channel_input_read");
-
- cpdata.flags &= ~SND_MIXER_DFLG_DECIBEL;
- crdata.flags &= ~SND_MIXER_DFLG_DECIBEL;
- if (volume) {
- if (mixer_input_volumes) {
- crdata.left = CLAMP(crdata.left + mixer_lvolume_delta, crinfo.min, crinfo.max);
- crdata.right = CLAMP(crdata.right + mixer_rvolume_delta, crinfo.min, crinfo.max);
- if (mixer_balance_volumes) {
- crdata.left = (crdata.left + crdata.right) / 2;
- crdata.right = crdata.left;
- }
- }
- else {
- cpdata.left = CLAMP(cpdata.left + mixer_lvolume_delta, cpinfo.min, cpinfo.max);
- cpdata.right = CLAMP(cpdata.right + mixer_rvolume_delta, cpinfo.min, cpinfo.max);
- if (mixer_balance_volumes) {
- cpdata.left = (cpdata.left + cpdata.right) / 2;
- cpdata.right = cpdata.left;
- }
- }
- }
- mixer_lvolume_delta = 0;
- mixer_rvolume_delta = 0;
- mixer_balance_volumes = 0;
-
- if (output) {
- if (mixer_toggle_mute_left) {
- cpdata.flags ^= SND_MIXER_DFLG_MUTE_LEFT;
- }
- if (mixer_toggle_mute_right) {
- cpdata.flags ^= SND_MIXER_DFLG_MUTE_RIGHT;
- }
- }
- mixer_toggle_mute_left = mixer_toggle_mute_right = 0;
-
- if (input) {
- if (mixer_toggle_record_left) {
- crdata.flags ^= SND_MIXER_DFLG_MUTE_LEFT;
- }
- if (mixer_toggle_record_right) {
- crdata.flags ^= SND_MIXER_DFLG_MUTE_RIGHT;
- }
-
- if (mixer_route_ltor_in) {
- crdata.flags ^= SND_MIXER_DFLG_LTOR;
- }
- if (mixer_route_rtol_in) {
- crdata.flags ^= SND_MIXER_DFLG_RTOL;
- }
- }
- mixer_toggle_record_left = mixer_toggle_record_right = 0;
- mixer_route_ltor_in = mixer_route_rtol_in = 0;
-
- if (output &&
- snd_mixer_channel_output_write(mixer_handle, channel_index, &cpdata) < 0)
- mixer_abort(ERR_FCN, "snd_mixer_channel_output_write");
- if (input &&
- snd_mixer_channel_input_write(mixer_handle, channel_index, &crdata) < 0)
- mixer_abort(ERR_FCN, "snd_mixer_channel_input_write");
- }
- /* first, read values for the numbers to be displayed in
- * specified EXACT mode
- */
- if (output &&
- snd_mixer_channel_output_read(mixer_handle, channel_index, &cpdata) < 0)
- mixer_abort(ERR_FCN, "snd_mixer_ioctl_channel_output_read");
- if (input &&
- snd_mixer_channel_input_read(mixer_handle, channel_index, &crdata) < 0)
- mixer_abort(ERR_FCN, "snd_mixer_channel_input_read");
- if (mixer_input_volumes) {
- if (input) {
- vleft = crdata.left;
- vright = crdata.right;
- }
- else {
- vleft = vright = 0;
- }
- }
- else {
- if (output) {
- vleft = cpdata.left;
- vright = cpdata.right;
- }
- else {
- vleft = vright = 0;
- }
- }
-
- /* then, always use percentage values for the bars. if we don't do
- * this, we will see aliasing effects on specific circumstances.
- * (actually they don't really dissapear, but they are transfered
- * to bar<->smaller-scale ambiguities).
- */
- if (mixer_exact) {
- i = 0;
- if (snd_mixer_exact_mode(mixer_handle, 0) < 0)
- mixer_abort(ERR_FCN, "snd_mixer_exact");
- if (output &&
- snd_mixer_channel_output_read(mixer_handle, channel_index, &cpdata) < 0)
- mixer_abort(ERR_FCN, "snd_mixer_channel_output_read");
- if (input &&
- snd_mixer_channel_input_read(mixer_handle, channel_index, &crdata) < 0)
- mixer_abort(ERR_FCN, "snd_mixer_channel_input_read");
- }
- /* get channel bar position
- */
- if (!mixer_cbar_get_pos(channel_index, &x, &y))
- return;
-
- /* channel bar name
- */
- mixer_dc(channel_index == mixer_focus_channel ? DC_CBAR_FOCUS_LABEL : DC_CBAR_LABEL);
- cinfo.name[8] = 0;
- for (i = 0; i < 8; i++) {
- string[i] = ' ';
- }
- sprintf(string + (8 - strlen(cinfo.name)) / 2, "%s ", cinfo.name);
- string[8] = 0;
- mvaddstr(y, x, string);
- y--;
-
- /* current channel values
- */
- mixer_dc(DC_BACK);
- mvaddstr(y, x, " ");
- mixer_dc(DC_TEXT);
- sprintf(string, "%d", vleft);
- mvaddstr(y, x + 3 - strlen(string), string);
- mixer_dc(DC_CBAR_FRAME);
- mvaddch(y, x + 3, '<');
- mvaddch(y, x + 4, '>');
- mixer_dc(DC_TEXT);
- sprintf(string, "%d", vright);
- mvaddstr(y, x + 5, string);
- y--;
-
- /* left/right bar
- */
- mixer_dc(DC_CBAR_FRAME);
- mvaddstr(y, x, " ");
- mvaddch(y, x + 2, ACS_LLCORNER);
- mvaddch(y, x + 3, ACS_HLINE);
- mvaddch(y, x + 4, ACS_HLINE);
- mvaddch(y, x + 5, ACS_LRCORNER);
- y--;
- for (i = 0; i < mixer_cbar_height; i++) {
- mvaddstr(y - i, x, " ");
- mvaddch(y - i, x + 2, ACS_VLINE);
- mvaddch(y - i, x + 5, ACS_VLINE);
- }
- string[2] = 0;
- for (i = 0; i < mixer_cbar_height; i++) {
- int dc;
-
- if (i + 1 >= 0.8 * mixer_cbar_height)
- dc = DC_CBAR_FULL_3;
- else if (i + 1 >= 0.4 * mixer_cbar_height)
- dc = DC_CBAR_FULL_2;
- else
- dc = DC_CBAR_FULL_1;
- mvaddch(y, x + 3, mixer_dc(vleft > i * 100 / mixer_cbar_height ? dc : DC_CBAR_EMPTY));
- mvaddch(y, x + 4, mixer_dc(vright > i * 100 / mixer_cbar_height ? dc : DC_CBAR_EMPTY));
- y--;
- }
-
- /* muted?
- */
- mixer_dc(DC_BACK);
- mvaddstr(y, x, " ");
- if (output) {
- c = (cpinfo.caps & SND_MIXER_CINFO_DCAP_MUTE) ? '-' : ' ';
- mixer_dc(DC_CBAR_FRAME);
- mvaddch(y, x + 2, ACS_ULCORNER);
- mvaddch(y, x + 3, mixer_dc(cpdata.flags & SND_MIXER_DFLG_MUTE_LEFT ?
- DC_CBAR_MUTE : DC_CBAR_NOMUTE));
- mvaddch(y, x + 4, mixer_dc(cpdata.flags & SND_MIXER_DFLG_MUTE_RIGHT ?
- DC_CBAR_MUTE : DC_CBAR_NOMUTE));
- mixer_dc(DC_CBAR_FRAME);
- mvaddch(y, x + 5, ACS_URCORNER);
- }
- y--;
-
- /* record input?
- */
- mixer_dc(DC_BACK);
- mvaddstr(y, x, " ");
- if (input) {
- if ((crdata.flags & SND_MIXER_DFLG_MUTE) != SND_MIXER_DFLG_MUTE) {
- mixer_dc(DC_CBAR_RECORD);
- mvaddstr(y, x + 1, "RECORD");
- if (!(crdata.flags & SND_MIXER_DFLG_MUTE_LEFT)) {
- if (crdata.flags & SND_MIXER_DFLG_LTOR)
- mvaddstr(y + 2, x + 6, "L");
- else
- mvaddstr(y + 1, x + 1, "L");
- }
- if (!(crdata.flags & SND_MIXER_DFLG_MUTE_RIGHT)) {
- if (crdata.flags & SND_MIXER_DFLG_RTOL)
- mvaddstr(y + 2, x + 1, "R");
- else
- mvaddstr(y + 1, x + 6, "R");
- }
- } else {
- for (i = 0; i < 6; i++)
- mvaddch(y, x + 1 + i, mixer_dc(DC_CBAR_NORECORD));
- }
- }
- y--;
-}
-
-static void mixer_update_cbars(void)
-{
- static int o_x = 0;
- static int o_y = 0;
- int i, x, y;
-
- if (!mixer_cbar_get_pos(mixer_focus_channel, &x, &y)) {
- if (mixer_focus_channel < mixer_first_vis_channel)
- mixer_first_vis_channel = mixer_focus_channel;
- else if (mixer_focus_channel >= mixer_first_vis_channel + mixer_n_vis_channels)
- mixer_first_vis_channel = mixer_focus_channel - mixer_n_vis_channels + 1;
- mixer_cbar_get_pos(mixer_focus_channel, &x, &y);
- }
- for (i = 0; i < mixer_n_vis_channels; i++)
- mixer_update_cbar(i + mixer_first_vis_channel);
-
- /* draw focused cbar
- */
- mixer_dc(DC_BACK);
- mvaddstr(o_y, o_x, " ");
- mvaddstr(o_y, o_x + 9, " ");
- o_x = x - 1;
- o_y = y;
- mixer_dc(DC_FOCUS);
- mvaddstr(o_y, o_x, "<");
- mvaddstr(o_y, o_x + 9, ">");
-}
-
-static void mixer_draw_frame(void)
-{
- char string[128];
- int i;
- int max_len;
-
- mixer_dc(DC_FRAME);
-
- /* corners
- */
- mvaddch(0, 0, ACS_ULCORNER);
- mvaddch(mixer_max_y - 1, 0, ACS_LLCORNER);
- mvaddch(mixer_max_y - 1, mixer_max_x - 1, ACS_LRCORNER);
- mvaddch(0, mixer_max_x - 1, ACS_URCORNER);
-
- /* lines
- */
- for (i = 1; i < mixer_max_y - 1; i++) {
- mvaddch(i, 0, ACS_VLINE);
- mvaddch(i, mixer_max_x - 1, ACS_VLINE);
- }
- for (i = 1; i < mixer_max_x - 1; i++) {
- mvaddch(0, i, ACS_HLINE);
- mvaddch(mixer_max_y - 1, i, ACS_HLINE);
- }
-
- /* program title
- */
- sprintf(string, "%s %s", PRGNAME_UPPER, VERSION);
- max_len = strlen(string);
- mvaddch(0, mixer_max_x / 2 - max_len / 2 - 1, '[');
- mvaddch(0, mixer_max_x / 2 - max_len / 2 + max_len, ']');
- mixer_dc(DC_TEXT);
- mvaddstr(0, mixer_max_x / 2 - max_len / 2, string);
- /* card name
- */
- mixer_dc(DC_PROMPT);
- mvaddstr(1, 2, "Card:");
- mixer_dc(DC_TEXT);
- sprintf(string, "%s", mixer_card_name);
- max_len = mixer_max_x - 2 - 6 - 2;
- if (strlen(string) > max_len)
- string[max_len] = 0;
- mvaddstr(1, 2 + 6, string);
-
- /* device name
- */
- mixer_dc(DC_PROMPT);
- mvaddstr(2, 2, "Chip: ");
- mixer_dc(DC_TEXT);
- sprintf(string, "%s", mixer_device_name);
- max_len = mixer_max_x - 2 - 6 - 2;
- if (strlen(string) > max_len)
- string[max_len] = 0;
- mvaddstr(2, 2 + 6, string);
- if (mixer_input_volumes)
- mvaddstr(3, 2, "Record mixer");
- else
- mvaddstr(3, 2, " ");
-}
-
-static void mixer_init(void)
-{
- static snd_mixer_info_t mixer_info =
- {0};
- static struct snd_ctl_hw_info hw_info;
- void *ctl_handle;
-
- if (snd_ctl_open(&ctl_handle, card_id) < 0)
- mixer_abort(ERR_OPEN, "snd_ctl_open");
- if (snd_ctl_hw_info(ctl_handle, &hw_info) < 0)
- mixer_abort(ERR_FCN, "snd_ctl_hw_info");
- snd_ctl_close(ctl_handle);
- /* open mixer device
- */
- if (snd_mixer_open(&mixer_handle, card_id, mixer_id) < 0)
- mixer_abort(ERR_OPEN, "snd_mixer_open");
-
- /* setup global variables
- */
- if (snd_mixer_info(mixer_handle, &mixer_info) < 0)
- mixer_abort(ERR_FCN, "snd_mixer_info");
- mixer_n_channels = mixer_info.channels;
- mixer_card_name = hw_info.name;
- mixer_device_name = mixer_info.name;
-}
-
-static void mixer_iteration_update(void *dummy, int channel)
-{
-#if 0
- fprintf(stderr, "*** channel = %i\n", channel);
-#endif
- mixer_update_cbar(channel);
- refresh();
-}
-
-static int mixer_iteration(void)
-{
- snd_mixer_callbacks_t callbacks;
- int key;
- int finished = 0;
- int mixer_fd;
- fd_set in;
-
- bzero(&callbacks, sizeof(callbacks));
- callbacks.channel_was_changed = mixer_iteration_update;
- callbacks.output_channel_was_changed = mixer_iteration_update;
- callbacks.input_channel_was_changed = mixer_iteration_update;
- mixer_fd = snd_mixer_file_descriptor(mixer_handle);
- while (1) {
- FD_ZERO(&in);
- FD_SET(fileno(stdin), &in);
- FD_SET(mixer_fd, &in);
- if (select(mixer_fd + 1, &in, NULL, NULL, NULL) <= 0)
- return 1;
- if (FD_ISSET(mixer_fd, &in))
- snd_mixer_read(mixer_handle, &callbacks);
- if (FD_ISSET(fileno(stdin), &in))
- break;
- }
- key = getch();
- switch (key) {
- case 27: /* Escape */
- finished = 1;
- break;
- case 9: /* Tab */
- mixer_exact = !mixer_exact;
- break;
- case KEY_RIGHT:
- case 'n':
- mixer_focus_channel += 1;
- break;
- case KEY_LEFT:
- case 'p':
- mixer_focus_channel -= 1;
- break;
- case KEY_PPAGE:
- if (mixer_exact) {
- mixer_lvolume_delta = 8;
- mixer_rvolume_delta = 8;
- } else {
- mixer_lvolume_delta = 10;
- mixer_rvolume_delta = 10;
- }
- break;
- case KEY_NPAGE:
- if (mixer_exact) {
- mixer_lvolume_delta = -8;
- mixer_rvolume_delta = -8;
- } else {
- mixer_lvolume_delta = -10;
- mixer_rvolume_delta = -10;
- }
- break;
- case KEY_BEG:
- case KEY_HOME:
- mixer_lvolume_delta = 512;
- mixer_rvolume_delta = 512;
- break;
- case KEY_LL:
- case KEY_END:
- mixer_lvolume_delta = -512;
- mixer_rvolume_delta = -512;
- break;
- case '+':
- mixer_lvolume_delta = 1;
- mixer_rvolume_delta = 1;
- break;
- case '-':
- mixer_lvolume_delta = -1;
- mixer_rvolume_delta = -1;
- break;
- case 'w':
- case KEY_UP:
- mixer_lvolume_delta = 1;
- mixer_rvolume_delta = 1;
- case 'W':
- mixer_lvolume_delta += 1;
- mixer_rvolume_delta += 1;
- break;
- case 'x':
- case KEY_DOWN:
- mixer_lvolume_delta = -1;
- mixer_rvolume_delta = -1;
- case 'X':
- mixer_lvolume_delta += -1;
- mixer_rvolume_delta += -1;
- break;
- case 'q':
- mixer_lvolume_delta = 1;
- case 'Q':
- mixer_lvolume_delta += 1;
- break;
- case 'y':
- case 'z':
- mixer_lvolume_delta = -1;
- case 'Y':
- case 'Z':
- mixer_lvolume_delta += -1;
- break;
- case 'e':
- mixer_rvolume_delta = 1;
- case 'E':
- mixer_rvolume_delta += 1;
- break;
- case 'c':
- mixer_rvolume_delta = -1;
- case 'C':
- mixer_rvolume_delta += -1;
- break;
- case 'm':
- case 'M':
- mixer_input_volumes = 0;
- mixer_toggle_mute_left = 1;
- mixer_toggle_mute_right = 1;
- break;
- case 'b':
- case 'B':
- case '=':
- mixer_balance_volumes = 1;
- break;
- case '<':
- case ',':
- mixer_input_volumes = 0;
- mixer_toggle_mute_left = 1;
- break;
- case '>':
- case '.':
- mixer_input_volumes = 0;
- mixer_toggle_mute_right = 1;
- break;
- case 'R':
- case 'r':
- mixer_input_volumes = !mixer_input_volumes;
- break;
- case 'L':
- case 'l':
- mixer_clear();
- break;
- case ' ':
- mixer_input_volumes = 1;
- mixer_toggle_record_left = 1;
- mixer_toggle_record_right = 1;
- break;
- case KEY_IC:
- case ';':
- mixer_input_volumes = 1;
- mixer_toggle_record_left = 1;
- break;
- case '\'':
- case KEY_DC:
- mixer_input_volumes = 1;
- mixer_toggle_record_right = 1;
- break;
- case '1':
- mixer_input_volumes = 1;
- mixer_route_rtol_in = 1;
- break;
- case '2':
- mixer_input_volumes = 1;
- mixer_route_ltor_in = 1;
- break;
- }
- mixer_focus_channel = CLAMP(mixer_focus_channel, 0, mixer_n_channels - 1);
-
- return finished;
-}
-
-static void mixer_init_screen(void)
+void main(void)
{
- signal(SIGWINCH, (void *) mixer_init_screen);
-
- getmaxyx(mixer_window, mixer_max_y, mixer_max_x);
- mixer_clear();
- mixer_max_x = MAX(MIXER_MIN_X, mixer_max_x);
- mixer_max_y = MAX(MIXER_MIN_Y, mixer_max_y);
- mixer_clear();
- mixer_ofs_x = 2;
- mixer_ofs_y = 2;
- mixer_extra_space = 0;
- mixer_n_vis_channels = MIN((mixer_max_x - 2 * mixer_ofs_x + 1) / (9 + mixer_extra_space),
- mixer_n_channels);
- mixer_extra_space = ((mixer_max_x - 2 * mixer_ofs_x - 1 - mixer_n_vis_channels * 9.0) /
- (mixer_n_vis_channels - 1));
- if (mixer_n_vis_channels < mixer_n_channels) {
- /* recalc
- */
- mixer_extra_space = MAX(mixer_extra_space, 1);
- mixer_n_vis_channels = MIN((mixer_max_x - 2 * mixer_ofs_x + 1) / (9 + mixer_extra_space),
- mixer_n_channels);
- mixer_extra_space = ((mixer_max_x - 2 * mixer_ofs_x - 1 - mixer_n_vis_channels * 9.0) /
- (mixer_n_vis_channels - 1));
- }
- mixer_first_vis_channel = 0;
- mixer_cbar_height = 10 + MAX(0, (mixer_max_y - MIXER_MIN_Y - 1)) / 2;
+ printf("TODO\n");
}
-
-static void mixer_signal_handler(int signal)
-{
- mixer_abort(ERR_SIGNAL, sys_siglist[signal]);
-}
-
-int main(int argc,
- char **argv)
-{
- int opt;
-
- /* parse args
- */
- do {
- opt = getopt(argc, argv, "c:m:ehg");
- switch (opt) {
- case '?':
- case 'h':
- fprintf(stderr, "%s %s\n", PRGNAME_UPPER, VERSION);
- fprintf(stderr, "Usage: %s [-e] [-c <card: 1..%i>] [-m <mixer: 0..1>]\n", PRGNAME, snd_cards());
- mixer_abort(ERR_NONE, "");
- case 'c':
- card_id = snd_card_name(optarg);
- break;
- case 'e':
- mixer_exact = !mixer_exact;
- break;
- case 'g':
- mixer_do_color = !mixer_do_color;
- break;
- case 'm':
- mixer_id = CLAMP(optarg[0], '0', '1') - '0';
- break;
- }
- }
- while (opt > 0);
-
- /* initialize mixer
- */
- mixer_init();
-
- /* setup signal handlers
- */
- signal(SIGINT, mixer_signal_handler);
- signal(SIGTRAP, mixer_signal_handler);
- signal(SIGABRT, mixer_signal_handler);
- signal(SIGQUIT, mixer_signal_handler);
- signal(SIGBUS, mixer_signal_handler);
- signal(SIGSEGV, mixer_signal_handler);
- signal(SIGPIPE, mixer_signal_handler);
- signal(SIGTERM, mixer_signal_handler);
-
- /* initialize ncurses
- */
- mixer_window = initscr();
- if (mixer_do_color)
- mixer_do_color = has_colors();
- mixer_init_draw_contexts();
- mixer_init_screen();
- if (mixer_max_x < MIXER_MIN_X ||
- mixer_max_y < MIXER_MIN_Y)
- mixer_abort(ERR_WINSIZE, "");
-
- /* react on key presses
- * and draw window
- */
- keypad(mixer_window, TRUE);
- leaveok(mixer_window, TRUE);
- cbreak();
- noecho();
- do {
- mixer_update_cbars();
- mixer_draw_frame();
- refresh();
- }
- while (!mixer_iteration());
-
- mixer_abort(ERR_NONE, "");
-};
--- /dev/null
+/* AlsaMixer - Commandline mixer for the ALSA project
+ * Copyright (C) 1998 Jaroslav Kysela <perex@jcu.cz>,
+ * Tim Janik <timj@gtk.org>,
+ * Carl van Schaik <carl@dreamcoat.che.uct.ac.za>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#include <errno.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/signal.h>
+
+#ifndef CURSESINC
+#include <ncurses.h>
+#else
+#include CURSESINC
+#endif
+#include <time.h>
+
+#include <sys/asoundlib.h>
+
+/* example compilation commandline:
+ * clear; gcc -Wall -pipe -O2 alsamixer.c -o alsamixer -lncurses
+ */
+
+/* --- defines --- */
+#define PRGNAME "alsamixer"
+#define PRGNAME_UPPER "AlsaMixer"
+#define VERSION "v0.9"
+
+#undef MAX
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#undef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#undef ABS
+#define ABS(a) (((a) < 0) ? -(a) : (a))
+#undef CLAMP
+#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
+
+#define MIXER_MIN_X (23) /* minimum: 23 */
+#define MIXER_MIN_Y (19) /* minimum: 19 */
+
+#define MIXER_BLACK (COLOR_BLACK)
+#define MIXER_DARK_RED (COLOR_RED)
+#define MIXER_RED (COLOR_RED | A_BOLD)
+#define MIXER_GREEN (COLOR_GREEN | A_BOLD)
+#define MIXER_ORANGE (COLOR_YELLOW)
+#define MIXER_YELLOW (COLOR_YELLOW | A_BOLD)
+#define MIXER_MARIN (COLOR_BLUE)
+#define MIXER_BLUE (COLOR_BLUE | A_BOLD)
+#define MIXER_MAGENTA (COLOR_MAGENTA)
+#define MIXER_DARK_CYAN (COLOR_CYAN)
+#define MIXER_CYAN (COLOR_CYAN | A_BOLD)
+#define MIXER_GREY (COLOR_WHITE)
+#define MIXER_GRAY (MIXER_GREY)
+#define MIXER_WHITE (COLOR_WHITE | A_BOLD)
+
+
+/* --- variables --- */
+static WINDOW *mixer_window = NULL;
+static int mixer_max_x = 0;
+static int mixer_max_y = 0;
+static int mixer_ofs_x = 0;
+static float mixer_extra_space = 0;
+static int mixer_ofs_y = 0;
+static int mixer_cbar_height = 0;
+
+static int card_id = 0;
+static int mixer_id = 0;
+static void *mixer_handle;
+static char *mixer_card_name = NULL;
+static char *mixer_device_name = NULL;
+
+static int mixer_n_channels = 0;
+static int mixer_n_vis_channels = 0;
+static int mixer_first_vis_channel = 0;
+static int mixer_focus_channel = 0;
+static int mixer_exact = 0;
+
+static int mixer_input_volumes = 0;
+
+static int mixer_lvolume_delta = 0;
+static int mixer_rvolume_delta = 0;
+static int mixer_balance_volumes = 0;
+static int mixer_toggle_mute_left = 0;
+static int mixer_toggle_mute_right = 0;
+
+/* By Carl */
+static int mixer_toggle_record_left = 0;
+static int mixer_toggle_record_right = 0;
+static int mixer_route_ltor_in = 0;
+static int mixer_route_rtol_in = 0;
+#if 0
+static int mixer_route_ltor_out = 0;
+static int mixer_route_rtol_out = 0;
+#endif
+
+
+/* --- draw contexts --- */
+enum {
+ DC_DEFAULT,
+ DC_BACK,
+ DC_TEXT,
+ DC_PROMPT,
+ DC_CBAR_MUTE,
+ DC_CBAR_NOMUTE,
+ DC_CBAR_RECORD,
+ DC_CBAR_NORECORD,
+ DC_CBAR_EMPTY,
+ DC_CBAR_FULL_1,
+ DC_CBAR_FULL_2,
+ DC_CBAR_FULL_3,
+ DC_CBAR_LABEL,
+ DC_CBAR_FOCUS_LABEL,
+ DC_FOCUS,
+ DC_LAST
+};
+
+static int dc_fg[DC_LAST] =
+{0};
+static int dc_attrib[DC_LAST] =
+{0};
+static int dc_char[DC_LAST] =
+{0};
+static int mixer_do_color = 1;
+
+static void mixer_init_dc(int c,
+ int n,
+ int f,
+ int b,
+ int a)
+{
+ dc_fg[n] = f;
+ dc_attrib[n] = a;
+ dc_char[n] = c;
+ if (n > 0)
+ init_pair(n, dc_fg[n] & 0xf, b & 0x0f);
+}
+
+static int mixer_dc(int n)
+{
+ if (mixer_do_color)
+ attrset(COLOR_PAIR(n) | (dc_fg[n] & 0xfffffff0));
+ else
+ attrset(dc_attrib[n]);
+
+ return dc_char[n];
+}
+
+static void mixer_init_draw_contexts(void)
+{
+ start_color();
+
+ mixer_init_dc('.', DC_BACK, MIXER_WHITE, MIXER_BLACK, A_NORMAL);
+ mixer_init_dc('.', DC_TEXT, MIXER_YELLOW, MIXER_BLACK, A_BOLD);
+ mixer_init_dc('.', DC_PROMPT, MIXER_DARK_CYAN, MIXER_BLACK, A_NORMAL);
+ mixer_init_dc('M', DC_CBAR_MUTE, MIXER_CYAN, MIXER_BLACK, A_BOLD);
+ mixer_init_dc('-', DC_CBAR_NOMUTE, MIXER_CYAN, MIXER_BLACK, A_NORMAL);
+ mixer_init_dc('x', DC_CBAR_RECORD, MIXER_DARK_RED, MIXER_BLACK, A_BOLD);
+ mixer_init_dc('-', DC_CBAR_NORECORD, MIXER_GRAY, MIXER_BLACK, A_NORMAL);
+ mixer_init_dc(' ', DC_CBAR_EMPTY, MIXER_GRAY, MIXER_BLACK, A_DIM);
+ mixer_init_dc('#', DC_CBAR_FULL_1, MIXER_WHITE, MIXER_BLACK, A_BOLD);
+ mixer_init_dc('#', DC_CBAR_FULL_2, MIXER_GREEN, MIXER_BLACK, A_BOLD);
+ mixer_init_dc('#', DC_CBAR_FULL_3, MIXER_RED, MIXER_BLACK, A_BOLD);
+ mixer_init_dc('.', DC_CBAR_LABEL, MIXER_WHITE, MIXER_BLUE, A_REVERSE | A_BOLD);
+ mixer_init_dc('.', DC_CBAR_FOCUS_LABEL, MIXER_RED, MIXER_BLUE, A_REVERSE | A_BOLD);
+ mixer_init_dc('.', DC_FOCUS, MIXER_RED, MIXER_BLACK, A_BOLD);
+}
+
+#define DC_CBAR_FRAME (DC_CBAR_MUTE)
+#define DC_FRAME (DC_PROMPT)
+
+
+/* --- error types --- */
+typedef enum {
+ ERR_NONE,
+ ERR_OPEN,
+ ERR_FCN,
+ ERR_SIGNAL,
+ ERR_WINSIZE,
+} ErrType;
+
+
+/* --- prototypes --- */
+static void mixer_abort(ErrType error,
+ const char *err_string)
+ __attribute__
+ ((noreturn));
+
+
+/* --- functions --- */
+static void mixer_clear(void)
+{
+ int x, y;
+
+ mixer_dc(DC_BACK);
+ clear();
+
+ /* buggy ncurses doesn't really write spaces with the specified
+ * color into the screen on clear ();
+ */
+ for (x = 0; x < mixer_max_x; x++)
+ for (y = 0; y < mixer_max_y; y++)
+ mvaddch(y, x, ' ');
+ refresh();
+}
+
+static void mixer_abort(ErrType error,
+ const char *err_string)
+{
+ if (mixer_window) {
+ mixer_clear();
+ endwin();
+ mixer_window = NULL;
+ }
+ printf("\n");
+
+ switch (error) {
+ case ERR_OPEN:
+ fprintf(stderr,
+ PRGNAME ": failed to open mixer #%i/#%i: %s\n",
+ card_id,
+ mixer_id,
+ snd_strerror(errno));
+ break;
+ case ERR_FCN:
+ fprintf(stderr,
+ PRGNAME ": function %s failed: %s\n",
+ err_string,
+ snd_strerror(errno));
+ break;
+ case ERR_SIGNAL:
+ fprintf(stderr,
+ PRGNAME ": aborting due to signal `%s'\n",
+ err_string);
+ break;
+ case ERR_WINSIZE:
+ fprintf(stderr,
+ PRGNAME ": screen size too small (%dx%d)\n",
+ mixer_max_x,
+ mixer_max_y);
+ break;
+ default:
+ break;
+ }
+
+ exit(error);
+}
+
+static int mixer_cbar_get_pos(int channel_index,
+ int *x_p,
+ int *y_p)
+{
+ int x;
+ int y;
+
+ if (channel_index < mixer_first_vis_channel ||
+ channel_index - mixer_first_vis_channel >= mixer_n_vis_channels)
+ return FALSE;
+
+ channel_index -= mixer_first_vis_channel;
+
+ x = mixer_ofs_x + 1;
+ y = mixer_ofs_y;
+ x += channel_index * (3 + 2 + 3 + 1 + mixer_extra_space);
+ y += mixer_max_y / 2;
+ y += mixer_cbar_height / 2 + 1;
+
+ if (x_p)
+ *x_p = x;
+ if (y_p)
+ *y_p = y;
+
+ return TRUE;
+}
+
+static void mixer_update_cbar(int channel_index)
+{
+ char string[64];
+ char c;
+ snd_mixer_channel_info_t cinfo =
+ {0};
+ snd_mixer_channel_direction_info_t cpinfo =
+ {0};
+ snd_mixer_channel_direction_info_t crinfo =
+ {0};
+ snd_mixer_channel_direction_t cpdata =
+ {0};
+ snd_mixer_channel_direction_t crdata =
+ {0};
+ int vleft, vright;
+ int x, y, i;
+ int output = 0, input = 0, volume;
+
+ /* set specified EXACT mode
+ */
+ if (snd_mixer_exact_mode(mixer_handle, mixer_exact) < 0)
+ mixer_abort(ERR_FCN, "snd_mixer_exact");
+
+ /* set new channel indices and read info
+ */
+ if (snd_mixer_channel_info(mixer_handle, channel_index, &cinfo) < 0)
+ mixer_abort(ERR_FCN, "snd_mixer_channel_info");
+ if (cinfo.caps & SND_MIXER_CINFO_CAP_OUTPUT) {
+ if (snd_mixer_channel_output_info(mixer_handle, channel_index, &cpinfo) < 0)
+ mixer_abort(ERR_FCN, "snd_mixer_channel_output_info");
+ output = 1;
+ }
+ if (cinfo.caps & SND_MIXER_CINFO_CAP_INPUT) {
+ if (snd_mixer_channel_input_info(mixer_handle, channel_index, &crinfo) < 0)
+ mixer_abort(ERR_FCN, "snd_mixer_channel_input_info");
+ input = 1;
+ }
+ if (mixer_input_volumes)
+ volume=(input && (crinfo.caps & SND_MIXER_CINFO_DCAP_VOLUME));
+ else
+ volume=(output && (cpinfo.caps & SND_MIXER_CINFO_DCAP_VOLUME));
+
+ /* set new channel values
+ */
+ if (channel_index == mixer_focus_channel &&
+ (mixer_lvolume_delta || mixer_rvolume_delta ||
+ mixer_toggle_mute_left || mixer_toggle_mute_right ||
+ mixer_balance_volumes ||
+ mixer_toggle_record_left || mixer_toggle_record_right ||
+ mixer_route_rtol_in || mixer_route_ltor_in)) {
+ if (output && snd_mixer_channel_output_read(mixer_handle, channel_index, &cpdata) < 0)
+ mixer_abort(ERR_FCN, "snd_mixer_channel_output_read");
+ if (input && snd_mixer_channel_input_read(mixer_handle, channel_index, &crdata) < 0)
+ mixer_abort(ERR_FCN, "snd_mixer_channel_input_read");
+
+ cpdata.flags &= ~SND_MIXER_DFLG_DECIBEL;
+ crdata.flags &= ~SND_MIXER_DFLG_DECIBEL;
+ if (volume) {
+ if (mixer_input_volumes) {
+ crdata.left = CLAMP(crdata.left + mixer_lvolume_delta, crinfo.min, crinfo.max);
+ crdata.right = CLAMP(crdata.right + mixer_rvolume_delta, crinfo.min, crinfo.max);
+ if (mixer_balance_volumes) {
+ crdata.left = (crdata.left + crdata.right) / 2;
+ crdata.right = crdata.left;
+ }
+ }
+ else {
+ cpdata.left = CLAMP(cpdata.left + mixer_lvolume_delta, cpinfo.min, cpinfo.max);
+ cpdata.right = CLAMP(cpdata.right + mixer_rvolume_delta, cpinfo.min, cpinfo.max);
+ if (mixer_balance_volumes) {
+ cpdata.left = (cpdata.left + cpdata.right) / 2;
+ cpdata.right = cpdata.left;
+ }
+ }
+ }
+ mixer_lvolume_delta = 0;
+ mixer_rvolume_delta = 0;
+ mixer_balance_volumes = 0;
+
+ if (output) {
+ if (mixer_toggle_mute_left) {
+ cpdata.flags ^= SND_MIXER_DFLG_MUTE_LEFT;
+ }
+ if (mixer_toggle_mute_right) {
+ cpdata.flags ^= SND_MIXER_DFLG_MUTE_RIGHT;
+ }
+ }
+ mixer_toggle_mute_left = mixer_toggle_mute_right = 0;
+
+ if (input) {
+ if (mixer_toggle_record_left) {
+ crdata.flags ^= SND_MIXER_DFLG_MUTE_LEFT;
+ }
+ if (mixer_toggle_record_right) {
+ crdata.flags ^= SND_MIXER_DFLG_MUTE_RIGHT;
+ }
+
+ if (mixer_route_ltor_in) {
+ crdata.flags ^= SND_MIXER_DFLG_LTOR;
+ }
+ if (mixer_route_rtol_in) {
+ crdata.flags ^= SND_MIXER_DFLG_RTOL;
+ }
+ }
+ mixer_toggle_record_left = mixer_toggle_record_right = 0;
+ mixer_route_ltor_in = mixer_route_rtol_in = 0;
+
+ if (output &&
+ snd_mixer_channel_output_write(mixer_handle, channel_index, &cpdata) < 0)
+ mixer_abort(ERR_FCN, "snd_mixer_channel_output_write");
+ if (input &&
+ snd_mixer_channel_input_write(mixer_handle, channel_index, &crdata) < 0)
+ mixer_abort(ERR_FCN, "snd_mixer_channel_input_write");
+ }
+ /* first, read values for the numbers to be displayed in
+ * specified EXACT mode
+ */
+ if (output &&
+ snd_mixer_channel_output_read(mixer_handle, channel_index, &cpdata) < 0)
+ mixer_abort(ERR_FCN, "snd_mixer_ioctl_channel_output_read");
+ if (input &&
+ snd_mixer_channel_input_read(mixer_handle, channel_index, &crdata) < 0)
+ mixer_abort(ERR_FCN, "snd_mixer_channel_input_read");
+ if (mixer_input_volumes) {
+ if (input) {
+ vleft = crdata.left;
+ vright = crdata.right;
+ }
+ else {
+ vleft = vright = 0;
+ }
+ }
+ else {
+ if (output) {
+ vleft = cpdata.left;
+ vright = cpdata.right;
+ }
+ else {
+ vleft = vright = 0;
+ }
+ }
+
+ /* then, always use percentage values for the bars. if we don't do
+ * this, we will see aliasing effects on specific circumstances.
+ * (actually they don't really dissapear, but they are transfered
+ * to bar<->smaller-scale ambiguities).
+ */
+ if (mixer_exact) {
+ i = 0;
+ if (snd_mixer_exact_mode(mixer_handle, 0) < 0)
+ mixer_abort(ERR_FCN, "snd_mixer_exact");
+ if (output &&
+ snd_mixer_channel_output_read(mixer_handle, channel_index, &cpdata) < 0)
+ mixer_abort(ERR_FCN, "snd_mixer_channel_output_read");
+ if (input &&
+ snd_mixer_channel_input_read(mixer_handle, channel_index, &crdata) < 0)
+ mixer_abort(ERR_FCN, "snd_mixer_channel_input_read");
+ }
+ /* get channel bar position
+ */
+ if (!mixer_cbar_get_pos(channel_index, &x, &y))
+ return;
+
+ /* channel bar name
+ */
+ mixer_dc(channel_index == mixer_focus_channel ? DC_CBAR_FOCUS_LABEL : DC_CBAR_LABEL);
+ cinfo.name[8] = 0;
+ for (i = 0; i < 8; i++) {
+ string[i] = ' ';
+ }
+ sprintf(string + (8 - strlen(cinfo.name)) / 2, "%s ", cinfo.name);
+ string[8] = 0;
+ mvaddstr(y, x, string);
+ y--;
+
+ /* current channel values
+ */
+ mixer_dc(DC_BACK);
+ mvaddstr(y, x, " ");
+ mixer_dc(DC_TEXT);
+ sprintf(string, "%d", vleft);
+ mvaddstr(y, x + 3 - strlen(string), string);
+ mixer_dc(DC_CBAR_FRAME);
+ mvaddch(y, x + 3, '<');
+ mvaddch(y, x + 4, '>');
+ mixer_dc(DC_TEXT);
+ sprintf(string, "%d", vright);
+ mvaddstr(y, x + 5, string);
+ y--;
+
+ /* left/right bar
+ */
+ mixer_dc(DC_CBAR_FRAME);
+ mvaddstr(y, x, " ");
+ mvaddch(y, x + 2, ACS_LLCORNER);
+ mvaddch(y, x + 3, ACS_HLINE);
+ mvaddch(y, x + 4, ACS_HLINE);
+ mvaddch(y, x + 5, ACS_LRCORNER);
+ y--;
+ for (i = 0; i < mixer_cbar_height; i++) {
+ mvaddstr(y - i, x, " ");
+ mvaddch(y - i, x + 2, ACS_VLINE);
+ mvaddch(y - i, x + 5, ACS_VLINE);
+ }
+ string[2] = 0;
+ for (i = 0; i < mixer_cbar_height; i++) {
+ int dc;
+
+ if (i + 1 >= 0.8 * mixer_cbar_height)
+ dc = DC_CBAR_FULL_3;
+ else if (i + 1 >= 0.4 * mixer_cbar_height)
+ dc = DC_CBAR_FULL_2;
+ else
+ dc = DC_CBAR_FULL_1;
+ mvaddch(y, x + 3, mixer_dc(vleft > i * 100 / mixer_cbar_height ? dc : DC_CBAR_EMPTY));
+ mvaddch(y, x + 4, mixer_dc(vright > i * 100 / mixer_cbar_height ? dc : DC_CBAR_EMPTY));
+ y--;
+ }
+
+ /* muted?
+ */
+ mixer_dc(DC_BACK);
+ mvaddstr(y, x, " ");
+ if (output) {
+ c = (cpinfo.caps & SND_MIXER_CINFO_DCAP_MUTE) ? '-' : ' ';
+ mixer_dc(DC_CBAR_FRAME);
+ mvaddch(y, x + 2, ACS_ULCORNER);
+ mvaddch(y, x + 3, mixer_dc(cpdata.flags & SND_MIXER_DFLG_MUTE_LEFT ?
+ DC_CBAR_MUTE : DC_CBAR_NOMUTE));
+ mvaddch(y, x + 4, mixer_dc(cpdata.flags & SND_MIXER_DFLG_MUTE_RIGHT ?
+ DC_CBAR_MUTE : DC_CBAR_NOMUTE));
+ mixer_dc(DC_CBAR_FRAME);
+ mvaddch(y, x + 5, ACS_URCORNER);
+ }
+ y--;
+
+ /* record input?
+ */
+ mixer_dc(DC_BACK);
+ mvaddstr(y, x, " ");
+ if (input) {
+ if ((crdata.flags & SND_MIXER_DFLG_MUTE) != SND_MIXER_DFLG_MUTE) {
+ mixer_dc(DC_CBAR_RECORD);
+ mvaddstr(y, x + 1, "RECORD");
+ if (!(crdata.flags & SND_MIXER_DFLG_MUTE_LEFT)) {
+ if (crdata.flags & SND_MIXER_DFLG_LTOR)
+ mvaddstr(y + 2, x + 6, "L");
+ else
+ mvaddstr(y + 1, x + 1, "L");
+ }
+ if (!(crdata.flags & SND_MIXER_DFLG_MUTE_RIGHT)) {
+ if (crdata.flags & SND_MIXER_DFLG_RTOL)
+ mvaddstr(y + 2, x + 1, "R");
+ else
+ mvaddstr(y + 1, x + 6, "R");
+ }
+ } else {
+ for (i = 0; i < 6; i++)
+ mvaddch(y, x + 1 + i, mixer_dc(DC_CBAR_NORECORD));
+ }
+ }
+ y--;
+}
+
+static void mixer_update_cbars(void)
+{
+ static int o_x = 0;
+ static int o_y = 0;
+ int i, x, y;
+
+ if (!mixer_cbar_get_pos(mixer_focus_channel, &x, &y)) {
+ if (mixer_focus_channel < mixer_first_vis_channel)
+ mixer_first_vis_channel = mixer_focus_channel;
+ else if (mixer_focus_channel >= mixer_first_vis_channel + mixer_n_vis_channels)
+ mixer_first_vis_channel = mixer_focus_channel - mixer_n_vis_channels + 1;
+ mixer_cbar_get_pos(mixer_focus_channel, &x, &y);
+ }
+ for (i = 0; i < mixer_n_vis_channels; i++)
+ mixer_update_cbar(i + mixer_first_vis_channel);
+
+ /* draw focused cbar
+ */
+ mixer_dc(DC_BACK);
+ mvaddstr(o_y, o_x, " ");
+ mvaddstr(o_y, o_x + 9, " ");
+ o_x = x - 1;
+ o_y = y;
+ mixer_dc(DC_FOCUS);
+ mvaddstr(o_y, o_x, "<");
+ mvaddstr(o_y, o_x + 9, ">");
+}
+
+static void mixer_draw_frame(void)
+{
+ char string[128];
+ int i;
+ int max_len;
+
+ mixer_dc(DC_FRAME);
+
+ /* corners
+ */
+ mvaddch(0, 0, ACS_ULCORNER);
+ mvaddch(mixer_max_y - 1, 0, ACS_LLCORNER);
+ mvaddch(mixer_max_y - 1, mixer_max_x - 1, ACS_LRCORNER);
+ mvaddch(0, mixer_max_x - 1, ACS_URCORNER);
+
+ /* lines
+ */
+ for (i = 1; i < mixer_max_y - 1; i++) {
+ mvaddch(i, 0, ACS_VLINE);
+ mvaddch(i, mixer_max_x - 1, ACS_VLINE);
+ }
+ for (i = 1; i < mixer_max_x - 1; i++) {
+ mvaddch(0, i, ACS_HLINE);
+ mvaddch(mixer_max_y - 1, i, ACS_HLINE);
+ }
+
+ /* program title
+ */
+ sprintf(string, "%s %s", PRGNAME_UPPER, VERSION);
+ max_len = strlen(string);
+ mvaddch(0, mixer_max_x / 2 - max_len / 2 - 1, '[');
+ mvaddch(0, mixer_max_x / 2 - max_len / 2 + max_len, ']');
+ mixer_dc(DC_TEXT);
+ mvaddstr(0, mixer_max_x / 2 - max_len / 2, string);
+
+ /* card name
+ */
+ mixer_dc(DC_PROMPT);
+ mvaddstr(1, 2, "Card:");
+ mixer_dc(DC_TEXT);
+ sprintf(string, "%s", mixer_card_name);
+ max_len = mixer_max_x - 2 - 6 - 2;
+ if (strlen(string) > max_len)
+ string[max_len] = 0;
+ mvaddstr(1, 2 + 6, string);
+
+ /* device name
+ */
+ mixer_dc(DC_PROMPT);
+ mvaddstr(2, 2, "Chip: ");
+ mixer_dc(DC_TEXT);
+ sprintf(string, "%s", mixer_device_name);
+ max_len = mixer_max_x - 2 - 6 - 2;
+ if (strlen(string) > max_len)
+ string[max_len] = 0;
+ mvaddstr(2, 2 + 6, string);
+ if (mixer_input_volumes)
+ mvaddstr(3, 2, "Record mixer");
+ else
+ mvaddstr(3, 2, " ");
+}
+
+static void mixer_init(void)
+{
+ static snd_mixer_info_t mixer_info =
+ {0};
+ static struct snd_ctl_hw_info hw_info;
+ void *ctl_handle;
+
+ if (snd_ctl_open(&ctl_handle, card_id) < 0)
+ mixer_abort(ERR_OPEN, "snd_ctl_open");
+ if (snd_ctl_hw_info(ctl_handle, &hw_info) < 0)
+ mixer_abort(ERR_FCN, "snd_ctl_hw_info");
+ snd_ctl_close(ctl_handle);
+ /* open mixer device
+ */
+ if (snd_mixer_open(&mixer_handle, card_id, mixer_id) < 0)
+ mixer_abort(ERR_OPEN, "snd_mixer_open");
+
+ /* setup global variables
+ */
+ if (snd_mixer_info(mixer_handle, &mixer_info) < 0)
+ mixer_abort(ERR_FCN, "snd_mixer_info");
+ mixer_n_channels = mixer_info.channels;
+ mixer_card_name = hw_info.name;
+ mixer_device_name = mixer_info.name;
+}
+
+static void mixer_iteration_update(void *dummy, int channel)
+{
+#if 0
+ fprintf(stderr, "*** channel = %i\n", channel);
+#endif
+ mixer_update_cbar(channel);
+ refresh();
+}
+
+static int mixer_iteration(void)
+{
+ snd_mixer_callbacks_t callbacks;
+ int key;
+ int finished = 0;
+ int mixer_fd;
+ fd_set in;
+
+ bzero(&callbacks, sizeof(callbacks));
+ callbacks.channel_was_changed = mixer_iteration_update;
+ callbacks.output_channel_was_changed = mixer_iteration_update;
+ callbacks.input_channel_was_changed = mixer_iteration_update;
+ mixer_fd = snd_mixer_file_descriptor(mixer_handle);
+ while (1) {
+ FD_ZERO(&in);
+ FD_SET(fileno(stdin), &in);
+ FD_SET(mixer_fd, &in);
+ if (select(mixer_fd + 1, &in, NULL, NULL, NULL) <= 0)
+ return 1;
+ if (FD_ISSET(mixer_fd, &in))
+ snd_mixer_read(mixer_handle, &callbacks);
+ if (FD_ISSET(fileno(stdin), &in))
+ break;
+ }
+ key = getch();
+ switch (key) {
+ case 27: /* Escape */
+ finished = 1;
+ break;
+ case 9: /* Tab */
+ mixer_exact = !mixer_exact;
+ break;
+ case KEY_RIGHT:
+ case 'n':
+ mixer_focus_channel += 1;
+ break;
+ case KEY_LEFT:
+ case 'p':
+ mixer_focus_channel -= 1;
+ break;
+ case KEY_PPAGE:
+ if (mixer_exact) {
+ mixer_lvolume_delta = 8;
+ mixer_rvolume_delta = 8;
+ } else {
+ mixer_lvolume_delta = 10;
+ mixer_rvolume_delta = 10;
+ }
+ break;
+ case KEY_NPAGE:
+ if (mixer_exact) {
+ mixer_lvolume_delta = -8;
+ mixer_rvolume_delta = -8;
+ } else {
+ mixer_lvolume_delta = -10;
+ mixer_rvolume_delta = -10;
+ }
+ break;
+ case KEY_BEG:
+ case KEY_HOME:
+ mixer_lvolume_delta = 512;
+ mixer_rvolume_delta = 512;
+ break;
+ case KEY_LL:
+ case KEY_END:
+ mixer_lvolume_delta = -512;
+ mixer_rvolume_delta = -512;
+ break;
+ case '+':
+ mixer_lvolume_delta = 1;
+ mixer_rvolume_delta = 1;
+ break;
+ case '-':
+ mixer_lvolume_delta = -1;
+ mixer_rvolume_delta = -1;
+ break;
+ case 'w':
+ case KEY_UP:
+ mixer_lvolume_delta = 1;
+ mixer_rvolume_delta = 1;
+ case 'W':
+ mixer_lvolume_delta += 1;
+ mixer_rvolume_delta += 1;
+ break;
+ case 'x':
+ case KEY_DOWN:
+ mixer_lvolume_delta = -1;
+ mixer_rvolume_delta = -1;
+ case 'X':
+ mixer_lvolume_delta += -1;
+ mixer_rvolume_delta += -1;
+ break;
+ case 'q':
+ mixer_lvolume_delta = 1;
+ case 'Q':
+ mixer_lvolume_delta += 1;
+ break;
+ case 'y':
+ case 'z':
+ mixer_lvolume_delta = -1;
+ case 'Y':
+ case 'Z':
+ mixer_lvolume_delta += -1;
+ break;
+ case 'e':
+ mixer_rvolume_delta = 1;
+ case 'E':
+ mixer_rvolume_delta += 1;
+ break;
+ case 'c':
+ mixer_rvolume_delta = -1;
+ case 'C':
+ mixer_rvolume_delta += -1;
+ break;
+ case 'm':
+ case 'M':
+ mixer_input_volumes = 0;
+ mixer_toggle_mute_left = 1;
+ mixer_toggle_mute_right = 1;
+ break;
+ case 'b':
+ case 'B':
+ case '=':
+ mixer_balance_volumes = 1;
+ break;
+ case '<':
+ case ',':
+ mixer_input_volumes = 0;
+ mixer_toggle_mute_left = 1;
+ break;
+ case '>':
+ case '.':
+ mixer_input_volumes = 0;
+ mixer_toggle_mute_right = 1;
+ break;
+ case 'R':
+ case 'r':
+ mixer_input_volumes = !mixer_input_volumes;
+ break;
+ case 'L':
+ case 'l':
+ mixer_clear();
+ break;
+ case ' ':
+ mixer_input_volumes = 1;
+ mixer_toggle_record_left = 1;
+ mixer_toggle_record_right = 1;
+ break;
+ case KEY_IC:
+ case ';':
+ mixer_input_volumes = 1;
+ mixer_toggle_record_left = 1;
+ break;
+ case '\'':
+ case KEY_DC:
+ mixer_input_volumes = 1;
+ mixer_toggle_record_right = 1;
+ break;
+ case '1':
+ mixer_input_volumes = 1;
+ mixer_route_rtol_in = 1;
+ break;
+ case '2':
+ mixer_input_volumes = 1;
+ mixer_route_ltor_in = 1;
+ break;
+ }
+ mixer_focus_channel = CLAMP(mixer_focus_channel, 0, mixer_n_channels - 1);
+
+ return finished;
+}
+
+static void mixer_init_screen(void)
+{
+ signal(SIGWINCH, (void *) mixer_init_screen);
+
+ getmaxyx(mixer_window, mixer_max_y, mixer_max_x);
+ mixer_clear();
+ mixer_max_x = MAX(MIXER_MIN_X, mixer_max_x);
+ mixer_max_y = MAX(MIXER_MIN_Y, mixer_max_y);
+ mixer_clear();
+ mixer_ofs_x = 2;
+ mixer_ofs_y = 2;
+ mixer_extra_space = 0;
+ mixer_n_vis_channels = MIN((mixer_max_x - 2 * mixer_ofs_x + 1) / (9 + mixer_extra_space),
+ mixer_n_channels);
+ mixer_extra_space = ((mixer_max_x - 2 * mixer_ofs_x - 1 - mixer_n_vis_channels * 9.0) /
+ (mixer_n_vis_channels - 1));
+ if (mixer_n_vis_channels < mixer_n_channels) {
+ /* recalc
+ */
+ mixer_extra_space = MAX(mixer_extra_space, 1);
+ mixer_n_vis_channels = MIN((mixer_max_x - 2 * mixer_ofs_x + 1) / (9 + mixer_extra_space),
+ mixer_n_channels);
+ mixer_extra_space = ((mixer_max_x - 2 * mixer_ofs_x - 1 - mixer_n_vis_channels * 9.0) /
+ (mixer_n_vis_channels - 1));
+ }
+ mixer_first_vis_channel = 0;
+ mixer_cbar_height = 10 + MAX(0, (mixer_max_y - MIXER_MIN_Y - 1)) / 2;
+}
+
+static void mixer_signal_handler(int signal)
+{
+ mixer_abort(ERR_SIGNAL, sys_siglist[signal]);
+}
+
+int main(int argc,
+ char **argv)
+{
+ int opt;
+
+ /* parse args
+ */
+ do {
+ opt = getopt(argc, argv, "c:m:ehg");
+ switch (opt) {
+ case '?':
+ case 'h':
+ fprintf(stderr, "%s %s\n", PRGNAME_UPPER, VERSION);
+ fprintf(stderr, "Usage: %s [-e] [-c <card: 1..%i>] [-m <mixer: 0..1>]\n", PRGNAME, snd_cards());
+ mixer_abort(ERR_NONE, "");
+ case 'c':
+ card_id = snd_card_name(optarg);
+ break;
+ case 'e':
+ mixer_exact = !mixer_exact;
+ break;
+ case 'g':
+ mixer_do_color = !mixer_do_color;
+ break;
+ case 'm':
+ mixer_id = CLAMP(optarg[0], '0', '1') - '0';
+ break;
+ }
+ }
+ while (opt > 0);
+
+ /* initialize mixer
+ */
+ mixer_init();
+
+ /* setup signal handlers
+ */
+ signal(SIGINT, mixer_signal_handler);
+ signal(SIGTRAP, mixer_signal_handler);
+ signal(SIGABRT, mixer_signal_handler);
+ signal(SIGQUIT, mixer_signal_handler);
+ signal(SIGBUS, mixer_signal_handler);
+ signal(SIGSEGV, mixer_signal_handler);
+ signal(SIGPIPE, mixer_signal_handler);
+ signal(SIGTERM, mixer_signal_handler);
+
+ /* initialize ncurses
+ */
+ mixer_window = initscr();
+ if (mixer_do_color)
+ mixer_do_color = has_colors();
+ mixer_init_draw_contexts();
+ mixer_init_screen();
+ if (mixer_max_x < MIXER_MIN_X ||
+ mixer_max_y < MIXER_MIN_Y)
+ mixer_abort(ERR_WINSIZE, "");
+
+ /* react on key presses
+ * and draw window
+ */
+ keypad(mixer_window, TRUE);
+ leaveok(mixer_window, TRUE);
+ cbreak();
+ noecho();
+ do {
+ mixer_update_cbars();
+ mixer_draw_frame();
+ refresh();
+ }
+ while (!mixer_iteration());
+
+ mixer_abort(ERR_NONE, "");
+};
INCLUDES = -I$(top_srcdir)/include
-LDADD = -lasound
+LDADD = -lasound -lm
EXTRA_DIST = README.first
bin_PROGRAMS = amixer
-amixer_SOURCES = amain.cpp amixer.cpp
-noinst_HEADERS = amixer.h atypes.h
+amixer_SOURCES = amixer.c
+noinst_HEADERS = amixer.h
man_MANS = amixer.1
+++ /dev/null
-Intro
------
-
-This is a quick mixer program for the ALSA project. It will grow out
-to include a GTK interface eventually, if noone beats me to it :)
-
-
-Building
---------
-
-Edit the Makefile where the -I (include option) is. This should
-point to the directory where the alsadriver is located. Then
-type "make" and it should build without complaining. If you have
-trouble with it please mail me at <arloafoe@cs.vu.nl>
-
-
-Running
--------
-
-amixer -h should display the syntax
-
-
-Bugs & Todo
------------
-
-A lot, let me know..
-
-
-Changes
--------
-
-v0.001 March 20 1998 - Initial code
-v0.1 Apr 21 1997 - Actually useful now
-
-
-Contact
--------
-Andy Lo A Foe
-arloafoe@cs.vu.nl
+++ /dev/null
-/*
- * Copyright 1998, Andy Lo A Foe <arloafoe@cs.vu.nl>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/asoundlib.h>
-#include "amixer.h"
-
-#define MIXER_RC ".amixerrc"
-
-char *rc_file(void)
-{
- static char rc_path[1024];
- char *p;
-
- p = getenv("HOME");
- if (p) {
- sprintf(rc_path, "%s/%s", p, MIXER_RC);
- } else {
- printf("Error reading HOME env. variable\n");
- return NULL;
- }
- return rc_path;
-}
-
-void copyright()
-{
- printf("CLI ALSA Mixer v0.11 (c) 1998 Adnans\n\n");
-}
-
-void usage()
-{
- printf("\n"
- "Usage: amixer [-c card] [-d dev] device [vol|L:R] [mute|unmute] [rec|norec]\n\n"
- " amixer [-p path] -r\tRead %s or <path> settings\n"
- " amixer [-p path] -w\tWrite %s or <path> settings\n"
- " amixer -q ...\t\tQuiet mode\n"
- " amixer -h\t\tHelp\n\n"
- "Example: amixer line-out 80:50 unmute rec\n\n", rc_file(), rc_file());
-}
-
-
-void read_config(Mixer * mix, const char *path)
-{
- FILE *rc;
- char buf[1024];
- int opt1;
- int opt2;
- int left, right;
- int dev;
- int count = 0;
- int flags;
-
- if (path && strcmp(path, "-") == 0)
- rc = stdin;
- else if ((rc = fopen(path ? path : rc_file(), "r")) == NULL) {
- printf("Mixer values not read\n");
- return;
- }
- while (!feof(rc) && fgets(buf, 1024, rc)) {
- count++;
- if (buf[0] == '\n')
- continue;
- if (buf[0] == '#' || strlen(buf) == 0)
- continue;
-
- if (sscanf(buf, "%d %d:%d %d %d\n", &dev, &left, &right, &opt1, &opt2) != 5) {
- printf("WARNING: unable to make out line %d of .rc file -> \"%s\"\n", count, buf);
- continue;
- }
- flags = 0;
- if (opt1)
- flags |= E_MIXER_MUTE;
- if (opt2)
- flags |= E_MIXER_RECORD;
- // Set mixer settings
- mix->DeviceSet(dev);
- mix->Write(left, right, flags);
- }
-
- if (rc != stdin)
- fclose(rc);
- return;
-}
-
-void write_config(Mixer * mix, const char *path)
-{
- FILE *rc;
- int32 left, right, flags;
-
- if (path && strcmp(path, "-") == 0)
- rc = stdout;
- else if ((rc = fopen(path ? path : rc_file(), "w+")) == NULL) {
- printf("Mixer values not written\n");
- return;
- }
- fprintf(rc, "# CLI ALSA mixer settings file. Autogenerated\n"
- "# Modify at your own risk :)\n\n");
- for (int i = 0; i < mix->NumDevices(); i++) {
- mix->DeviceSet(i);
- mix->Read(&left, &right, &flags);
- fprintf(rc, "%d %d:%d %d %d\n", i, mix->Left(), mix->Right(), flags & E_MIXER_MUTE ? 1 : 0, flags & E_MIXER_RECORD ? 1 : 0);
- }
- if (rc != stdout)
- fclose(rc);
- return;
-}
-
-int main(int argc, char **argv)
-{
- int card = 0, device = 0;
- char device_name[64] = "";
- int32 exact, mute, unmute, norec, rec, left, right, flags, device_index;
- int32 left_dB, right_dB;
- int32 cur_left, cur_right, cur_flags;
- int count, quiet = 0;
- int i, add;
- int pathind = 0;
- Mixer *the_mixer;
-
- exact = mute = rec = norec = unmute = device_index = left = right = -1;
- left_dB = right_dB = -1;
-
- for (add = 0; add + 1 < argc; i++) {
- if (!strcmp(argv[add + 1], "--help")) {
- usage();
- return 0;
- }
- if (argv[add + 1][0] == '-') {
- add++;
- if (argv[add][1] == 'c') {
- card = snd_card_name(argv[++add]);
- if (card < 0) {
- fprintf(stderr, "Invalid card: %s\n", argv[2]);
- exit(1);
- }
- } else if (argv[add][1] == 'd') {
- device = atoi(argv[++add]);
- if (device < 0 || device > 128) {
- fprintf(stderr, "Invalid device: %s\n", argv[2]);
- exit(1);
- }
- } else if (argv[add][1] == 'h') {
- usage();
- return 0;
- } else if (argv[add][1] == 'p') {
- pathind = ++add;
- } else if (argv[add][1] == 'r') {
- the_mixer = new Mixer(card, device);
- if (the_mixer && the_mixer->Init())
- read_config(the_mixer, pathind ? argv[pathind] : (const char *) NULL);
- delete the_mixer;
- return 0;
- } else if (argv[add][1] == 'w') {
- the_mixer = new Mixer(card, device);
- if (the_mixer && the_mixer->Init())
- write_config(the_mixer, pathind ? argv[pathind] : (const char *) NULL);
- delete the_mixer;
- return 0;
- } else if (argv[add][1] == 'q') {
- quiet = 1;
- } else {
- fprintf(stderr, "Invalid option: %s\n", argv[add] + 1);
- return 1;
- }
- } else {
- break;
- }
- }
- for (i = 1 + add; i < argc; i++) {
- if (strcmp(argv[i], "exact") == 0) {
- exact = 1;
- } else if (strcmp(argv[i], "mute") == 0) {
- mute = 1;
- } else if (strcmp(argv[i], "unmute") == 0) {
- unmute = 1;
- } else if (strcmp(argv[i], "rec") == 0) {
- rec = 1;
- } else if (strcmp(argv[i], "norec") == 0) {
- norec = 1;
- } else if (sscanf(argv[i], "%d:%d", &left, &right) == 2) {
- } else if (sscanf(argv[i], "%d", &left) == 1) {
- right = left;
- } else {
- strncpy(device_name, argv[i], sizeof(device_name));
- device_name[sizeof(device_name) - 1] = 0;
- }
- }
- Mixer mixer(card, device);
-
- if (mixer.Init() == false) {
- fprintf(stderr, "Failed to open mixer device\n");
- return 1;
- }
- count = mixer.NumDevices();
-
- for (i = 0; i < count; i++) {
- mixer.DeviceSet(i);
- if (strcasecmp(device_name, mixer.Name()) == 0)
- device_index = i;
- }
- if (!quiet)
- copyright();
- if (device_index >= 0) {
- mixer.DeviceSet(device_index);
- mixer.Read(&cur_left, &cur_right, &cur_flags);
- if (left >= 0)
- cur_left = left;
- if (right >= 0)
- cur_right = right;
- if (rec == 1)
- cur_flags |= E_MIXER_RECORD;
- else if (norec == 1)
- cur_flags &= ~E_MIXER_RECORD;
- if (mute == 1)
- cur_flags |= E_MIXER_MUTE;
- else if (unmute == 1)
- cur_flags &= ~E_MIXER_MUTE;
- if (left != -1 || rec != -1 || norec != -1 || mute != -1 || unmute != -1) {
- mixer.Write(cur_left, cur_right, cur_flags);
- }
- if (!quiet) {
- printf("%-16s", mixer.Name());
- mixer.Read(&left, &right, &flags);
- mixer.Read_dB(&left_dB, &right_dB);
- printf("%-3d%% (%6.2fdB) : %-3d%% (%6.2fdB) %s %s\n\n",
- left, ((float) left_dB) / 100.0,
- right, ((float) right_dB) / 100.0,
- (flags & E_MIXER_MUTE) ? "Mute" : " ",
- (flags & E_MIXER_RECORD) ? "Rec" : " ");
- }
- } else {
- if (quiet) {
- usage();
- return 1;
- }
- if (strlen(device_name))
- printf("Device not found: %s\n\n", device_name);
- for (i = 0; i < count; i++) {
- mixer.DeviceSet(i);
- printf("%-16s", mixer.Name());
- mixer.Read(&left, &right, &flags);
- mixer.Read_dB(&left_dB, &right_dB);
- printf("%-3d%% (%6.2fdB) : %-3d%% (%6.2fdB) %s %s\n",
- left, ((float) left_dB) / 100.0, right, ((float) right_dB) / 100.0,
- (flags & E_MIXER_MUTE) ? "Mute" : " ",
- (flags & E_MIXER_RECORD) ? "Rec" : " ");
- }
- return 0;
- }
-
- return 0;
-}
--- /dev/null
+/*
+ * ALSA command line mixer utility
+ * Copyright (c) 1999 by Jaroslav Kysela <perex@jcu.cz>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <math.h>
+#include <sys/asoundlib.h>
+#include "amixer.h"
+
+#define HELPID_HELP 1000
+#define HELPID_CARD 1001
+#define HELPID_DEVICE 1002
+#define HELPID_QUIET 1003
+#define HELPID_DEBUG 1004
+#define HELPID_VERSION 1005
+
+int quiet = 0;
+int debugflag = 0;
+int card;
+int device;
+
+struct mixer_types {
+ int type;
+ char *name;
+};
+
+struct mixer_types mixer_types[] = {
+ { SND_MIXER_ETYPE_INPUT, "Input" },
+ { SND_MIXER_ETYPE_OUTPUT, "Output" },
+ { SND_MIXER_ETYPE_CAPTURE, "Capture" },
+ { SND_MIXER_ETYPE_PLAYBACK, "Playback" },
+ { SND_MIXER_ETYPE_ADC, "ADC" },
+ { SND_MIXER_ETYPE_DAC, "DAC" },
+ { SND_MIXER_ETYPE_SWITCH1, "Switch1" },
+ { SND_MIXER_ETYPE_SWITCH2, "Switch2" },
+ { SND_MIXER_ETYPE_SWITCH3, "Switch3" },
+ { SND_MIXER_ETYPE_VOLUME1, "Volume1" },
+ { SND_MIXER_ETYPE_VOLUME2, "Volume2" },
+ { SND_MIXER_ETYPE_ACCU1, "Accumulator1" },
+ { SND_MIXER_ETYPE_ACCU2, "Accumulator2" },
+ { SND_MIXER_ETYPE_ACCU3, "Accumulator3" },
+ { SND_MIXER_ETYPE_MUX1, "Mux1" },
+ { SND_MIXER_ETYPE_MUX2, "Mux2" },
+ { SND_MIXER_ETYPE_TONE_CONTROL1, "ToneControl1" },
+ { SND_MIXER_ETYPE_EQUALIZER1, "Equalizer1" },
+ { SND_MIXER_ETYPE_3D_EFFECT1, "3D-Effect1" },
+ { SND_MIXER_ETYPE_PRE_EFFECT1, "PredefinedEffect1" },
+ { -1, NULL }
+};
+
+void error(const char *fmt,...)
+{
+ va_list va;
+
+ va_start(va, fmt);
+ fprintf(stderr, "amixer: ");
+ vfprintf(stderr, fmt, va);
+ fprintf(stderr, "\n");
+ va_end(va);
+}
+
+static void help(void)
+{
+ printf("Usage: amixer <options> command\n");
+ printf("\nAvailable options:\n");
+ printf(" -h,--help this help\n");
+ printf(" -c,--card # use a card number (0-%i) or the card name, default %i\n", snd_cards() - 1, card);
+ printf(" -d,--device # use a device number, default %i\n", device);
+ printf(" -D,--debug debug mode\n");
+ printf(" -v,--version print version of this program\n");
+ printf("\nAvailable commands:\n");
+ printf(" info show useful information for the selected mixer\n");
+ printf(" elements show information about all mixer elements\n");
+ printf(" contents show contents of all mixer elements\n");
+ printf(" groups show all mixer groups\n");
+ printf(" eset E P set extended setup for one mixer element\n");
+ printf(" eget E P get extended information for one mixer element\n");
+}
+
+int info(void)
+{
+ int err;
+ void *handle;
+ snd_mixer_info_t info;
+
+ if ((err = snd_mixer_open(&handle, card, device)) < 0) {
+ error("Mixer %i/%i open error: %s", card, device, snd_strerror(err));
+ return -1;
+ }
+ if ((err = snd_mixer_info(handle, &info)) < 0) {
+ error("Mixer %i/%i info error: %s", card, device, snd_strerror(err));
+ return -1;
+ }
+ printf("Mixer '%s/%s':\n", info.id, info.name);
+ printf(" Elements : %i\n", info.elements);
+ printf(" Groups : %i\n", info.groups);
+ printf(" Switches : %i\n", info.switches);
+ printf(" Attribute : 0x%x\n", info.attribute);
+ snd_mixer_close(handle);
+ return 0;
+}
+
+static const char *element_name(const char *name)
+{
+ static char res[25];
+
+ strncpy(res, name, 24);
+ res[24] = '\0';
+ return res;
+}
+
+static const char *element_type(int type)
+{
+ int idx;
+ static char str[32];
+
+ for (idx = 0; mixer_types[idx].type >= 0; idx++)
+ if (type == mixer_types[idx].type)
+ return mixer_types[idx].name;
+ sprintf(str, "Type%i", type);
+ return str;
+}
+
+static int check_range(int val, int min, int max)
+{
+ if (val < min)
+ return min;
+ if (val > max)
+ return max;
+ return val;
+}
+
+static int convert_range(int val, int omin, int omax, int nmin, int nmax)
+{
+ int orange = omax - omin, nrange = nmax - nmin;
+
+ if (orange == 0)
+ return 0;
+ return rint((((double)nrange * ((double)val - (double)omin)) + ((double)orange / 2.0)) / (double)orange + (double)nmin);
+}
+
+static int convert_db_range(int val, int omin, int omax, int nmin, int nmax)
+{
+ int orange = omax - omin, nrange = nmax - nmin;
+ int tmp;
+
+ if (orange == 0)
+ return 0;
+ tmp = rint((((double)nrange * ((double)val - (double)omin)) + ((double)orange / 2.0)) / (double)orange + (double)nmin);
+ return tmp;
+}
+
+static int convert_prange(int val, int min, int max)
+{
+ return convert_range(val, 0, 100, min, max);
+}
+
+static const char *get_percent(int val, int min, int max)
+{
+ static char str[32];
+ int p;
+
+ p = convert_range(val, min, max, 0, 100);
+ sprintf(str, "%i [%i%%]", val, p);
+ return str;
+}
+
+static const char *get_percent1(int val, int min, int max, int min_dB, int max_dB)
+{
+ static char str[32];
+ int p, db;
+
+ p = convert_range(val, min, max, 0, 100);
+ db = convert_db_range(val, min, max, min_dB, max_dB);
+ sprintf(str, "%i [%i%%] [%i.%02idB]", val, p, db / 100, abs(db % 100));
+ return str;
+}
+
+static int get_volume(char **ptr, int min, int max, int min_dB, int max_dB)
+{
+ int tmp, tmp1, tmp2;
+
+ if (**ptr == ':')
+ (*ptr)++;
+ if (**ptr == '\0' || (!isdigit(**ptr) && **ptr != '-'))
+ return min;
+ tmp = atoi(*ptr);
+ if (**ptr == '-')
+ (*ptr)++;
+ while (isdigit(**ptr))
+ (*ptr)++;
+ tmp1 = tmp;
+ tmp2 = 0;
+ if (**ptr == '.') {
+ (*ptr)++;
+ tmp2 = atoi(*ptr);
+ while (isdigit(**ptr))
+ (*ptr)++;
+ }
+ if (**ptr == '%') {
+ tmp1 = convert_prange(tmp, min, max);
+ (*ptr)++;
+ } else if (**ptr == 'd') {
+ tmp1 *= 100; tmp1 += tmp2 % 100;
+ tmp1 = convert_range(tmp1, min_dB, max_dB, min, max);
+ (*ptr)++;
+ }
+ tmp1 = check_range(tmp1, min, max);
+ if (**ptr == ',')
+ (*ptr)++;
+ return tmp1;
+}
+
+int show_element(void *handle, snd_mixer_eid_t *eid, const char *space)
+{
+ int err, idx;
+ snd_mixer_routes_t routes;
+ snd_mixer_eid_t *element;
+
+ bzero(&routes, sizeof(routes));
+ routes.eid = *eid;
+ if ((err = snd_mixer_routes(handle, &routes)) < 0) {
+ error("Mixer %i/%i route error: %s", card, device, snd_strerror(err));
+ return -1;
+ }
+ if (!routes.routes_over)
+ return 0;
+ routes.proutes = (snd_mixer_eid_t *)malloc(routes.routes_over * sizeof(snd_mixer_eid_t));
+ if (!routes.proutes) {
+ error("No enough memory...");
+ return -1;
+ }
+ routes.routes_size = routes.routes_over;
+ routes.routes = routes.routes_over = 0;
+ if ((err = snd_mixer_routes(handle, &routes)) < 0) {
+ error("Mixer %i/%i group (2) error: %s", card, device, snd_strerror(err));
+ return -1;
+ }
+ for (idx = 0; idx < routes.routes; idx++) {
+ element = &routes.proutes[idx];
+ printf("%sRoute to element '%s',%i,%s\n", space, element_name(element->name), element->index, element_type(element->type));
+ }
+ free(routes.proutes);
+ return 0;
+}
+
+static const char *speaker_position(int position)
+{
+ static char str[32];
+
+ switch (position) {
+ case SND_MIXER_VOICE_UNUSED:
+ return "Unused";
+ case SND_MIXER_VOICE_MONO:
+ return "Mono";
+ case SND_MIXER_VOICE_LEFT:
+ return "Left";
+ case SND_MIXER_VOICE_RIGHT:
+ return "Right";
+ case SND_MIXER_VOICE_CENTER:
+ return "Center";
+ case SND_MIXER_VOICE_REAR_LEFT:
+ return "Read-Left";
+ case SND_MIXER_VOICE_REAR_RIGHT:
+ return "Read-Right";
+ default:
+ sprintf(str, "Speaker%i", position);
+ return str;
+ }
+}
+
+int show_mux1_info(void *handle, snd_mixer_element_info_t *info, const char *space)
+{
+ int idx, idx1, err;
+ snd_mixer_elements_t elements;
+ snd_mixer_routes_t routes;
+ snd_mixer_eid_t *element;
+
+ printf("%sMux supports none input: %s\n", space, (info->data.mux1.attribute & SND_MIXER_MUX1_NONE) ? "YES" : "NO");
+ bzero(&elements, sizeof(elements));
+ if ((err = snd_mixer_elements(handle, &elements)) < 0) {
+ error("Mixer %i/%i elements error: %s", card, device, snd_strerror(err));
+ return -1;
+ }
+ elements.pelements = (snd_mixer_eid_t *)malloc(elements.elements_over * sizeof(snd_mixer_eid_t));
+ if (!elements.pelements) {
+ error("No enough memory");
+ return -1;
+ }
+ elements.elements_size = elements.elements_over;
+ elements.elements_over = elements.elements = 0;
+ if ((err = snd_mixer_elements(handle, &elements)) < 0) {
+ error("Mixer %i/%i elements (2) error: %s", card, device, snd_strerror(err));
+ return -1;
+ }
+ for (idx = 0; idx < elements.elements; idx++) {
+ bzero(&routes, sizeof(routes));
+ routes.eid = elements.pelements[idx];
+ if ((err = snd_mixer_routes(handle, &routes)) < 0) {
+ error("Mixer %i/%i route error: %s", card, device, snd_strerror(err));
+ free(elements.pelements);
+ return -1;
+ }
+ if (!routes.routes_over)
+ continue;
+ routes.proutes = (snd_mixer_eid_t *)malloc(routes.routes_over * sizeof(snd_mixer_eid_t));
+ if (!routes.proutes) {
+ error("No enough memory...");
+ free(elements.pelements);
+ return -1;
+ }
+ routes.routes_size = routes.routes_over;
+ routes.routes = routes.routes_over = 0;
+ if ((err = snd_mixer_routes(handle, &routes)) < 0) {
+ error("Mixer %i/%i group (2) error: %s", card, device, snd_strerror(err));
+ free(elements.pelements);
+ return -1;
+ }
+ for (idx1 = 0; idx1 < routes.routes; idx1++) {
+ element = &routes.proutes[idx1];
+ if (!strncmp(element->name, info->eid.name, sizeof(element->name)) &&
+ element->index == info->eid.index &&
+ element->type == info->eid.type)
+ printf("%sInput element '%s',%i,%s\n", space, element_name(routes.eid.name), routes.eid.index, element_type(routes.eid.type));
+ }
+ free(routes.proutes);
+ }
+ free(elements.pelements);
+ return 0;
+}
+
+int show_element_info(void *handle, snd_mixer_eid_t *eid, const char *space)
+{
+ int err, idx;
+ snd_mixer_element_info_t info;
+
+ if (snd_mixer_element_has_info(eid) != 1)
+ return 0;
+ bzero(&info, sizeof(info));
+ info.eid = *eid;
+ if ((err = snd_mixer_element_info_build(handle, &info)) < 0) {
+ error("Mixer %i/%i info error: %s", card, device, snd_strerror(err));
+ return -1;
+ }
+ switch (info.eid.type) {
+ case SND_MIXER_ETYPE_INPUT:
+ case SND_MIXER_ETYPE_OUTPUT:
+ if (info.data.io.attribute) {
+ printf("%sAttributes%s\n", space,
+ info.data.io.attribute & SND_MIXER_EIO_DIGITAL ? " digital" : "");
+ }
+ for (idx = 0; idx < info.data.io.voices; idx++) {
+ if (!info.data.io.pvoices[idx].vindex) {
+ printf("%sVoice %i: %s\n",
+ space,
+ idx,
+ speaker_position(info.data.io.pvoices[idx].voice));
+ } else {
+ printf("%sVoice %i: %i\n",
+ space,
+ idx,
+ info.data.io.pvoices[idx].voice);
+ }
+ }
+ break;
+ case SND_MIXER_ETYPE_CAPTURE:
+ case SND_MIXER_ETYPE_PLAYBACK:
+ for (idx = 0; idx < info.data.pcm.devices; idx++) {
+ printf("%sPCM device %i %i\n",
+ space,
+ idx,
+ info.data.pcm.pdevices[idx]);
+ }
+ break;
+ case SND_MIXER_ETYPE_ADC:
+ case SND_MIXER_ETYPE_DAC:
+ printf("%sResolution %i-bits\n", space, info.data.converter.resolution);
+ break;
+ case SND_MIXER_ETYPE_SWITCH3:
+ printf("%sSwitch type is ", space);
+ switch (info.data.switch3.type) {
+ case SND_MIXER_SWITCH3_FULL_FEATURED:
+ printf("full featured\n");
+ break;
+ case SND_MIXER_SWITCH3_ALWAYS_DESTINATION:
+ printf("always destination\n");
+ break;
+ case SND_MIXER_SWITCH3_ONE_DESTINATION:
+ printf("one destination\n");
+ break;
+ case SND_MIXER_SWITCH3_ALWAYS_ONE_DESTINATION:
+ printf("always one destination\n");
+ break;
+ default:
+ printf("unknown %i\n", info.data.switch3.type);
+ }
+ for (idx = 0; idx < info.data.switch3.voices; idx++) {
+ snd_mixer_voice_t voice = info.data.switch3.pvoices[idx];
+ if (voice.vindex) {
+ printf("%sVoice %i: %i\n", space, idx, voice.voice);
+ } else {
+ printf("%sSpeaker %i: %s\n", space, idx, speaker_position(voice.voice));
+ }
+ }
+ break;
+ case SND_MIXER_ETYPE_VOLUME1:
+ for (idx = 0; idx < info.data.volume1.range; idx++) {
+ struct snd_mixer_element_volume1_range *range = &info.data.volume1.prange[idx];
+ printf("%sVoice %i: Min %i (%i.%02idB), Max %i (%i.%02idB)\n",
+ space,
+ idx,
+ range->min, range->min_dB / 100, abs(range->min_dB % 100),
+ range->max, range->max_dB / 100, abs(range->max_dB % 100));
+ }
+ break;
+ case SND_MIXER_ETYPE_ACCU1:
+ printf("%sAttenuation %i.%02idB\n", space,
+ info.data.accu1.attenuation / 100,
+ abs(info.data.accu1.attenuation % 100));
+ break;
+ case SND_MIXER_ETYPE_ACCU2:
+ printf("%sAttenuation %i.%02idB\n", space,
+ info.data.accu2.attenuation / 100,
+ abs(info.data.accu1.attenuation % 100));
+ break;
+ case SND_MIXER_ETYPE_ACCU3:
+ for (idx = 0; idx < info.data.accu3.range; idx++) {
+ struct snd_mixer_element_accu3_range *range = &info.data.accu3.prange[idx];
+ printf("%sVoice %i: Min %i (%i.%02idB), Max %i (%i.%02idB)\n",
+ space,
+ idx,
+ range->min, range->min_dB / 100, abs(range->min_dB % 100),
+ range->max, range->max_dB / 100, abs(range->max_dB % 100));
+ }
+ break;
+ case SND_MIXER_ETYPE_MUX1:
+ show_mux1_info(handle, &info, space);
+ break;
+ case SND_MIXER_ETYPE_TONE_CONTROL1:
+ if (info.data.tc1.tc & SND_MIXER_TC1_SW)
+ printf("%sOn/Off switch\n", space);
+ if (info.data.tc1.tc & SND_MIXER_TC1_BASS)
+ printf("%sBass control: Min %i (%i.%02idB), Max %i (%i.%02idB)\n",
+ space,
+ info.data.tc1.min_bass,
+ info.data.tc1.min_bass_dB / 100,
+ abs(info.data.tc1.min_bass_dB % 100),
+ info.data.tc1.max_bass,
+ info.data.tc1.max_bass_dB / 100,
+ abs(info.data.tc1.max_bass_dB % 100));
+ if (info.data.tc1.tc & SND_MIXER_TC1_TREBLE)
+ printf("%sTreble control: Min %i (%i.%02idB), Max %i (%i.%02idB)\n",
+ space,
+ info.data.tc1.min_treble,
+ info.data.tc1.min_treble_dB / 100,
+ abs(info.data.tc1.min_treble_dB % 100),
+ info.data.tc1.max_treble,
+ info.data.tc1.max_treble_dB / 100,
+ abs(info.data.tc1.max_treble_dB % 100));
+ break;
+ case SND_MIXER_ETYPE_3D_EFFECT1:
+ if (info.data.teffect1.effect & SND_MIXER_EFF1_SW)
+ printf("%sOn/Off switch\n", space);
+ if (info.data.teffect1.effect & SND_MIXER_EFF1_MONO_SW)
+ printf("%sMono processing switch\n", space);
+ if (info.data.teffect1.effect & SND_MIXER_EFF1_WIDE)
+ printf("%sWide: Min %i, Max %i\n", space,
+ info.data.teffect1.min_wide,
+ info.data.teffect1.max_wide);
+ if (info.data.teffect1.effect & SND_MIXER_EFF1_VOLUME)
+ printf("%sVolume: Min %i, Max %i\n", space,
+ info.data.teffect1.min_volume,
+ info.data.teffect1.max_volume);
+ if (info.data.teffect1.effect & SND_MIXER_EFF1_CENTER)
+ printf("%sCenter: Min %i, Max %i\n", space,
+ info.data.teffect1.min_center,
+ info.data.teffect1.max_center);
+ if (info.data.teffect1.effect & SND_MIXER_EFF1_SPACE)
+ printf("%sSpace: Min %i, Max %i\n", space,
+ info.data.teffect1.min_space,
+ info.data.teffect1.max_space);
+ if (info.data.teffect1.effect & SND_MIXER_EFF1_DEPTH)
+ printf("%sDepth: Min %i, Max %i\n", space,
+ info.data.teffect1.min_depth,
+ info.data.teffect1.max_depth);
+ if (info.data.teffect1.effect & SND_MIXER_EFF1_DELAY)
+ printf("%sDelay: Min %i, Max %i\n", space,
+ info.data.teffect1.min_delay,
+ info.data.teffect1.max_delay);
+ if (info.data.teffect1.effect & SND_MIXER_EFF1_FEEDBACK)
+ printf("%sFeedback: Min %i, Max %i\n", space,
+ info.data.teffect1.min_feedback,
+ info.data.teffect1.max_feedback);
+ break;
+ default:
+ printf("%sInfo handler for type %i is not available\n", space, info.eid.type);
+ }
+ snd_mixer_element_info_free(&info);
+ return 0;
+}
+
+int show_element_contents(void *handle, snd_mixer_eid_t *eid, const char *space)
+{
+ int err, idx;
+ snd_mixer_element_t element;
+ snd_mixer_element_info_t info;
+
+ if (snd_mixer_element_has_control(eid) != 1)
+ return 0;
+ bzero(&element, sizeof(element));
+ bzero(&info, sizeof(info));
+ element.eid = info.eid = *eid;
+ if ((err = snd_mixer_element_build(handle, &element)) < 0) {
+ error("Mixer %i/%i element error: %s", card, device, snd_strerror(err));
+ return -1;
+ }
+ if (snd_mixer_element_has_info(eid) == 1) {
+ if ((err = snd_mixer_element_info_build(handle, &info)) < 0) {
+ error("Mixer %i/%i element error: %s", card, device, snd_strerror(err));
+ return -1;
+ }
+ }
+ switch (element.eid.type) {
+ case SND_MIXER_ETYPE_SWITCH1:
+ for (idx = 0; idx < element.data.switch1.sw; idx++) {
+ int val = snd_mixer_get_bit(element.data.switch1.psw, idx);
+ printf("%sVoice %i: Switch is %s\n", space, idx, val ? "ON" : "OFF");
+ }
+ break;
+ case SND_MIXER_ETYPE_SWITCH2:
+ printf("%sSwitch is %s\n", space, element.data.switch2.sw ? "ON" : "OFF");
+ break;
+ case SND_MIXER_ETYPE_SWITCH3:
+ if (element.data.switch3.rsw != info.data.switch3.voices * info.data.switch3.voices) {
+ error("Switch3 !!!\n");
+ goto __end;
+ }
+ for (idx = 0; idx < element.data.switch3.rsw; idx++) {
+ snd_mixer_voice_t input, output;
+ int val = snd_mixer_get_bit(element.data.switch3.prsw, idx);
+ printf("%sInput <", space);
+ input = info.data.switch3.pvoices[idx / info.data.switch3.voices];
+ output = info.data.switch3.pvoices[idx % info.data.switch3.voices];
+ if (input.vindex) {
+ printf("voice %i", input.voice);
+ } else {
+ printf(speaker_position(input.voice));
+ }
+ printf("> Output <");
+ if (output.vindex) {
+ printf("voice %i", output.voice);
+ } else {
+ printf(speaker_position(output.voice));
+ }
+ printf(">: Switch is %s\n", val ? "ON" : "OFF");
+ }
+ break;
+ case SND_MIXER_ETYPE_VOLUME1:
+ for (idx = 0; idx < element.data.volume1.voices; idx++) {
+ int val = element.data.volume1.pvoices[idx];
+ printf("%sVoice %i: Value %s\n", space, idx,
+ get_percent1(val, info.data.volume1.prange[idx].min,
+ info.data.volume1.prange[idx].max,
+ info.data.volume1.prange[idx].min_dB,
+ info.data.volume1.prange[idx].max_dB));
+ }
+ break;
+ case SND_MIXER_ETYPE_ACCU3:
+ for (idx = 0; idx < element.data.accu3.voices; idx++) {
+ int val = element.data.accu3.pvoices[idx];
+ printf("%sVoice %i: Value %s\n", space, idx,
+ get_percent1(val, info.data.accu3.prange[idx].min,
+ info.data.accu3.prange[idx].max,
+ info.data.accu3.prange[idx].min_dB,
+ info.data.accu3.prange[idx].max_dB));
+ }
+ break;
+ case SND_MIXER_ETYPE_MUX1:
+ for (idx = 0; idx < element.data.mux1.output; idx++) {
+ snd_mixer_eid_t *eid = &element.data.mux1.poutput[idx];
+ printf("%sVoice %i: Element '%s',%i,%i\n", space, idx,
+ element_name(eid->name),
+ eid->index, eid->type);
+ }
+ break;
+ case SND_MIXER_ETYPE_TONE_CONTROL1:
+ if (element.data.tc1.tc & SND_MIXER_TC1_SW)
+ printf("%sOn/Off switch is %s\n", space, element.data.tc1.sw ? "ON" : "OFF");
+ if (element.data.tc1.tc & SND_MIXER_TC1_BASS)
+ printf("%sBass: %s\n", space, get_percent1(element.data.tc1.bass, info.data.tc1.min_bass, info.data.tc1.max_bass, info.data.tc1.min_bass_dB, info.data.tc1.max_bass_dB));
+ if (element.data.tc1.tc & SND_MIXER_TC1_TREBLE)
+ printf("%sTreble: %s\n", space, get_percent1(element.data.tc1.treble, info.data.tc1.min_treble, info.data.tc1.max_treble, info.data.tc1.min_treble_dB, info.data.tc1.max_treble_dB));
+ break;
+ case SND_MIXER_ETYPE_3D_EFFECT1:
+ if (element.data.teffect1.effect & SND_MIXER_EFF1_SW)
+ printf("%sOn/Off switch is %s\n", space, element.data.teffect1.sw ? "ON" : "OFF");
+ if (element.data.teffect1.effect & SND_MIXER_EFF1_MONO_SW)
+ printf("%sMono processing switch is %s\n", space, element.data.teffect1.mono_sw ? "ON" : "OFF");
+ if (element.data.teffect1.effect & SND_MIXER_EFF1_WIDE)
+ printf("%sWide: %s\n", space, get_percent(element.data.teffect1.wide, info.data.teffect1.min_wide, info.data.teffect1.max_wide));
+ if (element.data.teffect1.effect & SND_MIXER_EFF1_VOLUME)
+ printf("%sVolume: %s\n", space, get_percent(element.data.teffect1.volume, info.data.teffect1.min_volume, info.data.teffect1.max_volume));
+ if (element.data.teffect1.effect & SND_MIXER_EFF1_CENTER)
+ printf("%sCenter: %s\n", space, get_percent(element.data.teffect1.center, info.data.teffect1.min_center, info.data.teffect1.max_center));
+ if (element.data.teffect1.effect & SND_MIXER_EFF1_SPACE)
+ printf("%sSpace: %s\n", space, get_percent(element.data.teffect1.space, info.data.teffect1.min_space, info.data.teffect1.max_space));
+ if (element.data.teffect1.effect & SND_MIXER_EFF1_DEPTH)
+ printf("%sDepth: %s\n", space, get_percent(element.data.teffect1.depth, info.data.teffect1.min_depth, info.data.teffect1.max_depth));
+ if (element.data.teffect1.effect & SND_MIXER_EFF1_DELAY)
+ printf("%sDelay: %s\n", space, get_percent(element.data.teffect1.delay, info.data.teffect1.min_delay, info.data.teffect1.max_delay));
+ if (element.data.teffect1.effect & SND_MIXER_EFF1_FEEDBACK)
+ printf("%sFeedback: %s\n", space, get_percent(element.data.teffect1.feedback, info.data.teffect1.min_feedback, info.data.teffect1.max_feedback));
+ break;
+ default:
+ printf("%sRead handler for type %i is not available\n", space, element.eid.type);
+ }
+ __end:
+ snd_mixer_element_free(&element);
+ if (snd_mixer_element_has_info(eid))
+ snd_mixer_element_info_free(&info);
+ return 0;
+}
+
+int elements(void)
+{
+ int err, idx;
+ void *handle;
+ snd_mixer_elements_t elements;
+ snd_mixer_eid_t *element;
+
+ if ((err = snd_mixer_open(&handle, card, device)) < 0) {
+ error("Mixer %i/%i open error: %s", card, device, snd_strerror(err));
+ return -1;
+ }
+ bzero(&elements, sizeof(elements));
+ if ((err = snd_mixer_elements(handle, &elements)) < 0) {
+ error("Mixer %i/%i elements error: %s", card, device, snd_strerror(err));
+ return -1;
+ }
+ elements.pelements = (snd_mixer_eid_t *)malloc(elements.elements_over * sizeof(snd_mixer_eid_t));
+ if (!elements.pelements) {
+ error("No enough memory");
+ return -1;
+ }
+ elements.elements_size = elements.elements_over;
+ elements.elements_over = elements.elements = 0;
+ if ((err = snd_mixer_elements(handle, &elements)) < 0) {
+ error("Mixer %i/%i elements (2) error: %s", card, device, snd_strerror(err));
+ return -1;
+ }
+ for (idx = 0; idx < elements.elements; idx++) {
+ element = &elements.pelements[idx];
+ printf("Element '%s',%i,%s\n", element_name(element->name), element->index, element_type(element->type));
+ show_element(handle, element, " ");
+ show_element_info(handle, element, " ");
+ }
+ free(elements.pelements);
+ snd_mixer_close(handle);
+ return 0;
+}
+
+int elements_contents(void)
+{
+ int err, idx;
+ void *handle;
+ snd_mixer_elements_t elements;
+ snd_mixer_eid_t *element;
+
+ if ((err = snd_mixer_open(&handle, card, device)) < 0) {
+ error("Mixer %i/%i open error: %s", card, device, snd_strerror(err));
+ return -1;
+ }
+ bzero(&elements, sizeof(elements));
+ if ((err = snd_mixer_elements(handle, &elements)) < 0) {
+ error("Mixer %i/%i elements error: %s", card, device, snd_strerror(err));
+ return -1;
+ }
+ elements.pelements = (snd_mixer_eid_t *)malloc(elements.elements_over * sizeof(snd_mixer_eid_t));
+ if (!elements.pelements) {
+ error("No enough memory");
+ return -1;
+ }
+ elements.elements_size = elements.elements_over;
+ elements.elements_over = elements.elements = 0;
+ if ((err = snd_mixer_elements(handle, &elements)) < 0) {
+ error("Mixer %i/%i elements (2) error: %s", card, device, snd_strerror(err));
+ return -1;
+ }
+ for (idx = 0; idx < elements.elements; idx++) {
+ element = &elements.pelements[idx];
+ printf("Element '%s',%i,%s\n", element_name(element->name), element->index, element_type(element->type));
+ show_element_info(handle, element, " ");
+ show_element_contents(handle, element, " ");
+ }
+ free(elements.pelements);
+ snd_mixer_close(handle);
+ return 0;
+}
+
+static const char *group_name(const char *name)
+{
+ static char res[25];
+
+ strncpy(res, name, 24);
+ res[24] = '\0';
+ return res;
+}
+
+int show_group(void *handle, snd_mixer_gid_t *gid, const char *space)
+{
+ int err, idx;
+ snd_mixer_group_t group;
+ snd_mixer_eid_t *element;
+
+ bzero(&group, sizeof(group));
+ group.gid = *gid;
+ if ((err = snd_mixer_group(handle, &group)) < 0) {
+ error("Mixer %i/%i group error: %s", card, device, snd_strerror(err));
+ return -1;
+ }
+ group.pelements = (snd_mixer_eid_t *)malloc(group.elements_over * sizeof(snd_mixer_eid_t));
+ if (!group.pelements) {
+ error("No enough memory...");
+ return -1;
+ }
+ group.elements_size = group.elements_over;
+ group.elements = group.elements_over = 0;
+ if ((err = snd_mixer_group(handle, &group)) < 0) {
+ error("Mixer %i/%i group (2) error: %s", card, device, snd_strerror(err));
+ return -1;
+ }
+ for (idx = 0; idx < group.elements; idx++) {
+ element = &group.pelements[idx];
+ printf("%sElement '%s',%i,%s\n", space, element_name(element->name), element->index, element_type(element->type));
+ }
+ free(group.pelements);
+ return 0;
+}
+
+int groups(void)
+{
+ int err, idx;
+ void *handle;
+ snd_mixer_groups_t groups;
+ snd_mixer_gid_t *group;
+
+ if ((err = snd_mixer_open(&handle, card, device)) < 0) {
+ error("Mixer %i/%i open error: %s", card, device, snd_strerror(err));
+ return -1;
+ }
+ bzero(&groups, sizeof(groups));
+ if ((err = snd_mixer_groups(handle, &groups)) < 0) {
+ error("Mixer %i/%i groups error: %s", card, device, snd_strerror(err));
+ return -1;
+ }
+ groups.pgroups = (snd_mixer_gid_t *)malloc(groups.groups_over * sizeof(snd_mixer_eid_t));
+ if (!groups.pgroups) {
+ error("No enough memory");
+ return -1;
+ }
+ groups.groups_size = groups.groups_over;
+ groups.groups_over = groups.groups = 0;
+ if ((err = snd_mixer_groups(handle, &groups)) < 0) {
+ error("Mixer %i/%i groups (2) error: %s", card, device, snd_strerror(err));
+ return -1;
+ }
+ for (idx = 0; idx < groups.groups; idx++) {
+ group = &groups.pgroups[idx];
+ printf("Group '%s', %i\n", group_name(group->name), group->index);
+ show_group(handle, group, " ");
+ }
+ free(groups.pgroups);
+ snd_mixer_close(handle);
+ return 0;
+}
+
+static int parse_eid(const char *str, snd_mixer_eid_t *eid)
+{
+ int c, size, idx;
+ char *ptr;
+
+ while (*str == ' ' || *str == '\t')
+ str++;
+ if (!(*str))
+ return 1;
+ bzero(eid, sizeof(*eid));
+ ptr = eid->name;
+ size = 0;
+ if (*str != '"' && *str != '\'') {
+ while (*str && *str != ',') {
+ if (size < sizeof(eid->name)) {
+ *ptr++ = *str;
+ size++;
+ }
+ str++;
+ }
+ } else {
+ c = *str++;
+ while (*str && *str != c) {
+ if (size < sizeof(eid->name)) {
+ *ptr++ = *str;
+ size++;
+ }
+ str++;
+ }
+ if (*str == c)
+ str++;
+ }
+ if (*str != ',')
+ return 1;
+ str++;
+ if (!isdigit(*str))
+ return 1;
+ eid->type = atoi(str);
+ while (isdigit(*str))
+ str++;
+ if (*str != ',')
+ return 1;
+ str++;
+ if (isdigit(*str)) {
+ eid->type = atoi(str);
+ return 0;
+ } else {
+ for (idx = 0; mixer_types[idx].type >= 0; idx++)
+ if (!strncmp(mixer_types[idx].name, str, strlen(mixer_types[idx].name))) {
+ eid->type = mixer_types[idx].type;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+int eset_switch1(int argc, char *argv[], void *handle, snd_mixer_eid_t *eid)
+{
+ int err, tmp, idx = 0;
+ snd_mixer_element_t element;
+ char *ptr;
+
+ if (argc != 1) {
+ fprintf(stderr, "The set Switch1 command requires an argument:\n");
+ fprintf(stderr, " on/off[,on/off] ...\n");
+ return 1;
+ }
+ bzero(&element, sizeof(element));
+ element.eid = *eid;
+ if ((err = snd_mixer_element_build(handle, &element)) < 0) {
+ error("Mixer element build error: %s", snd_strerror(err));
+ return 1;
+ }
+ if (!strcmp(argv[0], "on") || !strcmp(argv[0], "off")) {
+ tmp = !strcmp(argv[0], "on");
+ for (idx = 0; idx < element.data.switch1.sw; idx++)
+ snd_mixer_set_bit(element.data.switch1.psw, idx, tmp);
+ } else {
+ ptr = argv[idx];
+ for (idx = 0; idx < element.data.switch1.sw; idx++) {
+ tmp = !strncmp(ptr, "on", 2);
+ snd_mixer_set_bit(element.data.switch1.psw, idx, tmp);
+ while (*ptr && *ptr != ',')
+ ptr++;
+ if (*ptr == ',')
+ ptr++;
+ }
+ }
+ if ((err = snd_mixer_element_write(handle, &element)) < 0) {
+ error("Mixer element write error: %s\n", snd_strerror(err));
+ snd_mixer_element_free(&element);
+ return 1;
+ }
+ snd_mixer_element_free(&element);
+ return 0;
+}
+
+int eset_switch2(int argc, char *argv[], void *handle, snd_mixer_eid_t *eid)
+{
+ int err;
+ snd_mixer_element_t element;
+
+ if (argc != 1) {
+ fprintf(stderr, "The set Switch2 command requires an argument:\n");
+ fprintf(stderr, " on/off\n");
+ return 1;
+ }
+ bzero(&element, sizeof(element));
+ element.eid = *eid;
+ if ((err = snd_mixer_element_build(handle, &element)) < 0) {
+ error("Mixer element build error: %s", snd_strerror(err));
+ return 1;
+ }
+ element.data.switch2.sw = !strcmp(argv[0], "on") ? 1 : 0;
+ if ((err = snd_mixer_element_write(handle, &element)) < 0) {
+ error("Mixer element write error: %s\n", snd_strerror(err));
+ snd_mixer_element_free(&element);
+ return 1;
+ }
+ snd_mixer_element_free(&element);
+ return 0;
+}
+
+int eset_volume1(int argc, char *argv[], void *handle, snd_mixer_eid_t *eid)
+{
+ int err, tmp, idx = 0;
+ snd_mixer_element_t element;
+ snd_mixer_element_info_t info;
+ char *ptr;
+
+ if (argc != 1 || (!isdigit(*argv[0]) && *argv[0] != ':')) {
+ fprintf(stderr, "The set Volume1 command requires an argument:\n");
+ fprintf(stderr, " vol[,vol] ...\n");
+ return 1;
+ }
+ bzero(&info, sizeof(info));
+ info.eid = *eid;
+ if ((err = snd_mixer_element_info_build(handle, &info)) < 0) {
+ error("Mixer element read error: %s", snd_strerror(err));
+ return 1;
+ }
+ bzero(&element, sizeof(element));
+ element.eid = *eid;
+ if ((err = snd_mixer_element_build(handle, &element)) < 0) {
+ error("Mixer element read error: %s", snd_strerror(err));
+ snd_mixer_element_info_free(&info);
+ return 1;
+ }
+ if (!strchr(argv[0], ',')) {
+ for (idx = 0; idx < element.data.volume1.voices; idx++) {
+ ptr = argv[0];
+ tmp = get_volume(&ptr,
+ info.data.volume1.prange[idx].min,
+ info.data.volume1.prange[idx].max,
+ info.data.volume1.prange[idx].min_dB,
+ info.data.volume1.prange[idx].max_dB);
+ element.data.volume1.pvoices[idx] = tmp;
+ }
+ } else {
+ ptr = argv[idx];
+ for (idx = 0; idx < element.data.volume1.voices; idx++) {
+ tmp = get_volume(&ptr,
+ info.data.volume1.prange[idx].min,
+ info.data.volume1.prange[idx].max,
+ info.data.volume1.prange[idx].min_dB,
+ info.data.volume1.prange[idx].max_dB);
+ element.data.volume1.pvoices[idx] = tmp;
+ }
+ }
+ if ((err = snd_mixer_element_write(handle, &element)) < 0) {
+ error("Mixer element write error: %s\n", snd_strerror(err));
+ snd_mixer_element_free(&element);
+ snd_mixer_element_info_free(&info);
+ return 1;
+ }
+ snd_mixer_element_free(&element);
+ snd_mixer_element_info_free(&info);
+ return 0;
+}
+
+int eset_accu3(int argc, char *argv[], void *handle, snd_mixer_eid_t *eid)
+{
+ int err, tmp, idx = 0;
+ snd_mixer_element_t element;
+ snd_mixer_element_info_t info;
+ char *ptr;
+
+ if (argc != 1 || (!isdigit(*argv[0]) && *argv[0] != ':')) {
+ fprintf(stderr, "The set Accu3 command requires an argument:\n");
+ fprintf(stderr, " vol[,vol] ...\n");
+ return 1;
+ }
+ bzero(&info, sizeof(info));
+ info.eid = *eid;
+ if ((err = snd_mixer_element_info_build(handle, &info)) < 0) {
+ error("Mixer element read error: %s", snd_strerror(err));
+ return 1;
+ }
+ bzero(&element, sizeof(element));
+ element.eid = *eid;
+ if ((err = snd_mixer_element_build(handle, &element)) < 0) {
+ error("Mixer element read error: %s", snd_strerror(err));
+ snd_mixer_element_info_free(&info);
+ return 1;
+ }
+ if (!strchr(argv[0], ',')) {
+ for (idx = 0; idx < element.data.accu3.voices; idx++) {
+ ptr = argv[0];
+ tmp = get_volume(&ptr,
+ info.data.accu3.prange[idx].min,
+ info.data.accu3.prange[idx].max,
+ info.data.accu3.prange[idx].min_dB,
+ info.data.accu3.prange[idx].max_dB);
+ element.data.accu3.pvoices[idx] = tmp;
+ }
+ } else {
+ ptr = argv[idx];
+ for (idx = 0; idx < element.data.volume1.voices; idx++) {
+ tmp = get_volume(&ptr,
+ info.data.accu3.prange[idx].min,
+ info.data.accu3.prange[idx].max,
+ info.data.accu3.prange[idx].min_dB,
+ info.data.accu3.prange[idx].max_dB);
+ element.data.accu3.pvoices[idx] = tmp;
+ }
+ }
+ if ((err = snd_mixer_element_write(handle, &element)) < 0) {
+ error("Mixer element write error: %s\n", snd_strerror(err));
+ snd_mixer_element_free(&element);
+ snd_mixer_element_info_free(&info);
+ return 1;
+ }
+ snd_mixer_element_free(&element);
+ snd_mixer_element_info_free(&info);
+ return 0;
+}
+
+int eset_mux1(int argc, char *argv[], void *handle, snd_mixer_eid_t *eid)
+{
+ int err, idx = 0;
+ snd_mixer_element_t element;
+ snd_mixer_element_info_t info;
+ snd_mixer_eid_t xeid;
+
+ if (argc < 1) {
+ fprintf(stderr, "The set Mux1 command requires an argument:\n");
+ fprintf(stderr, " element[ element] ...\n");
+ return 1;
+ }
+ bzero(&info, sizeof(info));
+ info.eid = *eid;
+ if ((err = snd_mixer_element_info_build(handle, &info)) < 0) {
+ error("Mixer element read error: %s", snd_strerror(err));
+ return 1;
+ }
+ bzero(&element, sizeof(element));
+ element.eid = *eid;
+ if ((err = snd_mixer_element_build(handle, &element)) < 0) {
+ error("Mixer element read error: %s", snd_strerror(err));
+ snd_mixer_element_info_free(&info);
+ return 1;
+ }
+ if (argc == 1) {
+ if (parse_eid(argv[0], &xeid)) {
+ fprintf(stderr, "Wrong element identifier: %s\n", argv[0]);
+ snd_mixer_element_free(&element);
+ snd_mixer_element_info_free(&info);
+ return 1;
+ }
+ for (idx = 0; idx < element.data.mux1.output; idx++)
+ element.data.mux1.poutput[idx] = xeid;
+ } else {
+ for (idx = 0; idx < element.data.volume1.voices; idx++) {
+ if (parse_eid(argv[idx >= argc ? argc - 1 : idx], &xeid)) {
+ fprintf(stderr, "Wrong element identifier: %s\n", argv[0]);
+ snd_mixer_element_free(&element);
+ snd_mixer_element_info_free(&info);
+ return 1;
+ }
+ element.data.mux1.poutput[idx] = xeid;
+ }
+ }
+ if ((err = snd_mixer_element_write(handle, &element)) < 0) {
+ error("Mixer element write error: %s\n", snd_strerror(err));
+ snd_mixer_element_free(&element);
+ snd_mixer_element_info_free(&info);
+ return 1;
+ }
+ snd_mixer_element_free(&element);
+ snd_mixer_element_info_free(&info);
+ return 0;
+}
+
+int eset(int argc, char *argv[])
+{
+ int err;
+ void *handle;
+ snd_mixer_eid_t eid;
+
+ if (argc < 1) {
+ fprintf(stderr, "Specify a full element identifier: 'name',index,type\n");
+ return 1;
+ }
+ if (parse_eid(argv[0], &eid)) {
+ fprintf(stderr, "Wrong element identifier: %s\n", argv[0]);
+ return 1;
+ }
+ if ((err = snd_mixer_open(&handle, card, device)) < 0) {
+ error("Mixer %i/%i open error: %s\n", card, device, snd_strerror(err));
+ return -1;
+ }
+ if (!quiet) {
+ printf("Element '%s',%i,%s\n", element_name(eid.name), eid.index, element_type(eid.type));
+ }
+ switch (eid.type) {
+ case SND_MIXER_ETYPE_SWITCH1:
+ if (eset_switch1(argc - 1, argv + 1, handle, &eid))
+ goto __end;
+ break;
+ case SND_MIXER_ETYPE_SWITCH2:
+ if (eset_switch2(argc - 1, argv + 1, handle, &eid))
+ goto __end;
+ break;
+ case SND_MIXER_ETYPE_VOLUME1:
+ if (eset_volume1(argc - 1, argv + 1, handle, &eid))
+ goto __end;
+ break;
+ case SND_MIXER_ETYPE_ACCU3:
+ if (eset_accu3(argc - 1, argv + 1, handle, &eid))
+ goto __end;
+ break;
+ case SND_MIXER_ETYPE_MUX1:
+ if (eset_mux1(argc - 1, argv + 1, handle, &eid))
+ goto __end;
+ break;
+ }
+ if (!quiet) {
+ if (snd_mixer_element_has_info(&eid)) {
+ show_element_info(handle, &eid, " ");
+ }
+ if (snd_mixer_element_has_control(&eid)) {
+ show_element_contents(handle, &eid, " ");
+ }
+ }
+ __end:
+ snd_mixer_close(handle);
+ return 0;
+}
+
+int eget(int argc, char *argv[])
+{
+ int err;
+ void *handle;
+ snd_mixer_eid_t eid;
+
+ if (argc < 1) {
+ fprintf(stderr, "Specify a full element identifier: 'name',index,type\n");
+ return 1;
+ }
+ if (parse_eid(argv[0], &eid)) {
+ fprintf(stderr, "Wrong element identifier: %s\n", argv[0]);
+ return 1;
+ }
+ if ((err = snd_mixer_open(&handle, card, device)) < 0) {
+ error("Mixer %i/%i open error: %s\n", card, device, snd_strerror(err));
+ return -1;
+ }
+ printf("Element '%s',%i,%s\n", element_name(eid.name), eid.index, element_type(eid.type));
+ if (show_element(handle, &eid, " ") >= 0) {
+ if (snd_mixer_element_has_info(&eid)) {
+ show_element_info(handle, &eid, " ");
+ }
+ if (snd_mixer_element_has_control(&eid)) {
+ show_element_contents(handle, &eid, " ");
+ }
+ }
+ snd_mixer_close(handle);
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int morehelp;
+ struct option long_option[] =
+ {
+ {"help", 0, NULL, HELPID_HELP},
+ {"card", 1, NULL, HELPID_CARD},
+ {"device", 1, NULL, HELPID_DEVICE},
+ {"quiet", 0, NULL, HELPID_QUIET},
+ {"debug", 0, NULL, HELPID_DEBUG},
+ {"version", 0, NULL, HELPID_VERSION},
+ {NULL, 0, NULL, 0},
+ };
+
+ morehelp = 0;
+ card = snd_defaults_mixer_card();
+ device = snd_defaults_mixer_device();
+ if (card < 0 || device < 0) {
+ fprintf(stderr, "The ALSA sound driver was not detected in this system.\n");
+ return 1;
+ }
+ while (1) {
+ int c;
+
+ if ((c = getopt_long(argc, argv, "hc:d:qDv", long_option, NULL)) < 0)
+ break;
+ switch (c) {
+ case 'h':
+ case HELPID_HELP:
+ morehelp++;
+ break;
+ case 'c':
+ case HELPID_CARD:
+ card = snd_card_name(optarg);
+ break;
+ case 'd':
+ case HELPID_DEVICE:
+ device = device;
+ break;
+ case 'q':
+ case HELPID_QUIET:
+ quiet = 1;
+ break;
+ case 'D':
+ case HELPID_DEBUG:
+ debugflag = 1;
+ break;
+ case 'v':
+ case HELPID_VERSION:
+ printf("amixer version " SND_UTIL_VERSION_STR "\n");
+ return 1;
+ default:
+ fprintf(stderr, "\07Invalid switch or option needs an argument.\n");
+ morehelp++;
+ }
+ }
+ if (morehelp) {
+ help();
+ return 1;
+ }
+ if (argc - optind <= 0) {
+ fprintf(stderr, "amixer: Specify command...\n");
+ return 0;
+ }
+ if (!strcmp(argv[optind], "info")) {
+ return info() ? 1 : 0;
+ } else if (!strcmp(argv[optind], "elements")) {
+ return elements() ? 1 : 0;
+ } else if (!strcmp(argv[optind], "contents")) {
+ return elements_contents() ? 1 : 0;
+ } else if (!strcmp(argv[optind], "groups")) {
+ return groups() ? 1 : 0;
+ } else if (!strcmp(argv[optind], "eset")) {
+ return eset(argc - optind - 1, argc - optind > 1 ? argv + optind + 1 : NULL) ? 1 : 0;
+ } else if (!strcmp(argv[optind], "eget")) {
+ return eget(argc - optind - 1, argc - optind > 1 ? argv + optind + 1 : NULL) ? 1 : 0;
+ } else {
+ fprintf(stderr, "amixer: Unknown command '%s'...\n", argv[optind]);
+ }
+
+ return 0;
+}
+++ /dev/null
-/*
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/asoundlib.h>
-#include "amixer.h"
-
-
-Mixer::Mixer(int card, int device)
-{
- mixer_handle = NULL;
-
- if (snd_mixer_open(&mixer_handle, card, device) < 0) {
- fprintf(stderr, "Can't access mixer %i/%i\n", card+1, device);
- mixer_status = ~E_MIXER_SUCCESS;
- return;
- }
- mixer_status = E_MIXER_SUCCESS;
- mixer_status |= E_MIXER_NEED_CLOSE;
-}
-
-
-bool Mixer::Open(int card, int device)
-{
- Close();
- if (snd_mixer_open(&mixer_handle, card, device) < 0) {
- fprintf(stderr, "Can't access mixer %i/%i\n", card + 1, device);
- mixer_status = ~E_MIXER_SUCCESS;
- } else{
- mixer_status = E_MIXER_SUCCESS;
- mixer_status |= E_MIXER_NEED_CLOSE;
- }
- return Init();
-}
-
-
-void Mixer::Close()
-{
- if (mixer_handle != NULL && mixer_status & E_MIXER_NEED_CLOSE) {
- snd_mixer_close(mixer_handle);
- }
- mixer_handle = NULL;
- mixer_status = ~E_MIXER_SUCCESS;
-}
-
-
-Mixer::~Mixer()
-{
- Close();
-}
-
-
-bool Mixer::Init()
-{
- if (!(mixer_status & E_MIXER_SUCCESS))
- return false;
- if ((nr_devices = snd_mixer_channels(mixer_handle)) < 0)
- return false;
-
- return true;
-}
-
-
-
-char* Mixer::Name()
-{
- return Name(current_device);
-}
-
-char* Mixer::Name(int32 device)
-{
- if (snd_mixer_channel_info(mixer_handle,device,&ch_info) < 0)
- return "Unknown";
- return (char *)ch_info.name;
-}
-
-void Mixer::Update()
-{
- if(snd_mixer_channel_output_read(mixer_handle, current_device, &ch_data) < 0) {
- fprintf(stderr, "Can't read data from channel %i\n", current_device);
- return; /* No fail code? */
- }
-}
-
-void Mixer::DeviceRead(int32 device, int32 *left, int32 *right, int32 *flags)
-{
- current_device = device;
- Update();
- *left = ch_data.left;
- *right = ch_data.right;
- *flags = ch_data.flags;
-}
-
-
-void Mixer::DeviceWrite(int32 device, int32 left, int32 right, int32 flags)
-{
- current_device = device;
- ch_data.channel = device;
- ch_data.left = left;
- ch_data.right = right;
- ch_data.flags = flags;
- if(snd_mixer_channel_output_write(mixer_handle, device, &ch_data) < 0) {
- fprintf(stderr, "Can't write data to channel %i\n", device);
- return; /* No fail code? */
- }
-}
-
/*
+ * ALSA command line mixer utility
+ * Copyright (c) 1999 by Jaroslav Kysela <perex@jcu.cz>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
*
*/
-#include "atypes.h"
-
-#define E_MIXER_SUCCESS 1
-#define E_MIXER_NEED_CLOSE 2
-
-/* FIXME */
-#define E_MIXER_RECORD 0
-
-#define E_MIXER_MUTE_LEFT SND_MIXER_DFLG_MUTE_LEFT
-#define E_MIXER_MUTE_RIGHT SND_MIXER_DFLG_MUTE_RIGHT
-#define E_MIXER_MUTE SND_MIXER_DFLG_MUTE
-
-
-class Mixer
-{
-public:
- Mixer(int card = 0, int device = 0);
- ~Mixer();
- bool Init();
- bool Open(int card, int device);
- void Close();
- void DeviceSet(int32 device) {
- current_device = device;
- Update();
- }
- char* Name(int32 device);
- char* Name();
- int32 NumDevices() { return nr_devices; }
- void Update();
- void DeviceRead(int32 device, int32 *left, int32 *right, int32 *flag);
- void DeviceWrite(int32 device, int32 left, int32 right, int32 flag);
- void Read(int32 *left, int32 *right, int32 *flags) {
- DeviceRead(current_device, left, right, flags);
- }
- void Read_dB(int32 *left_dB, int32 *right_dB) {
- *left_dB = ch_data.left_dB;
- *right_dB = ch_data.right_dB;
- }
- void Write(int32 left, int32 right, int32 flags) {
- DeviceWrite(current_device, left, right, flags);
- }
- int Left() { return ch_data.left; }
- int Right() { return ch_data.right; }
- Mixer& operator[](int32 device) {
- DeviceSet(device);
- return (*this);
- }
-private:
- snd_mixer_info_t info;
- snd_mixer_channel_direction_t ch_data;
- snd_mixer_channel_info_t ch_info;
-
- void * mixer_handle;
- int32 mixer_status;
- int32 current_device;
- int32 nr_devices;
-};
+#include "../include/version.h"
+++ /dev/null
-typedef int int32;