mirror of
https://github.com/alsa-project/alsa-utils
synced 2024-11-08 21:45:44 +01:00
Mixer v2.0 merged to the main CVS tree...
This commit is contained in:
parent
daab0cd6d0
commit
2e02eadd72
16 changed files with 3759 additions and 2048 deletions
|
@ -2,5 +2,10 @@ sbin_PROGRAMS=alsactl
|
|||
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
|
||||
|
||||
|
|
|
@ -64,28 +64,6 @@ static void help(void)
|
|||
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;
|
||||
|
@ -101,12 +79,18 @@ static int store_setup(const char *cardname)
|
|||
soundcard_setup_init();
|
||||
for (idx = 0; idx < 32; idx++) {
|
||||
if (card_mask & (1 << idx)) { /* find each installed soundcards */
|
||||
if ((err = soundcard_setup_collect(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;
|
||||
|
||||
|
@ -115,17 +99,17 @@ static int store_setup(const char *cardname)
|
|||
error("Cannot find soundcard '%s'...", cardname);
|
||||
return 1;
|
||||
}
|
||||
if ((err = collect_all()))
|
||||
return err;
|
||||
if ((err = soundcard_setup_load(cfgfile, 1)))
|
||||
return err;
|
||||
if ((err = soundcard_setup_collect(cardno))) {
|
||||
if ((err = soundcard_setup_collect_switches(cardno))) {
|
||||
soundcard_setup_done();
|
||||
return err;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -140,11 +124,32 @@ static int restore_setup(const char *cardname)
|
|||
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;
|
||||
}
|
||||
|
@ -210,5 +215,3 @@ int main(int argc, char *argv[])
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -48,21 +48,16 @@ struct ctl {
|
|||
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;
|
||||
};
|
||||
|
@ -93,10 +88,17 @@ struct soundcard {
|
|||
};
|
||||
|
||||
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);
|
||||
|
|
|
@ -22,6 +22,12 @@
|
|||
%{
|
||||
|
||||
#include "alsactl.h"
|
||||
|
||||
struct bytearray {
|
||||
unsigned char *data;
|
||||
size_t datalen;
|
||||
};
|
||||
|
||||
#include "alsactl_parser.h"
|
||||
|
||||
#define YY_NO_UNPUT
|
||||
|
@ -41,15 +47,14 @@ int linecount;
|
|||
"["|"]" 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;
|
||||
|
@ -71,8 +76,29 @@ type return L_TYPE;
|
|||
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 */
|
||||
|
||||
|
@ -81,9 +107,9 @@ true|on|yes return L_TRUE;
|
|||
|
||||
/* 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 */
|
||||
|
@ -92,25 +118,27 @@ true|on|yes return L_TRUE;
|
|||
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 */
|
||||
|
|
|
@ -32,36 +32,53 @@ extern char cfgfile[];
|
|||
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 build_soundcard(char *name);
|
||||
static void build_mixer(char *name);
|
||||
static void build_pcm(char *name);
|
||||
static void build_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);
|
||||
static void build_mixer_element(char *name, int index, int etype);
|
||||
|
||||
#define SWITCH_CONTROL 0
|
||||
#define SWITCH_MIXER 1
|
||||
#define SWITCH_PCM 2
|
||||
#define SWITCH_RAWMIDI 3
|
||||
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 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 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);
|
||||
|
||||
|
@ -71,10 +88,8 @@ static struct soundcard *Xsoundcard = NULL;
|
|||
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];
|
||||
|
||||
|
@ -86,7 +101,7 @@ 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
|
||||
|
@ -101,15 +116,20 @@ static unsigned short Xswitchiec958ocs1[16];
|
|||
/* 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
|
||||
|
||||
%%
|
||||
|
||||
|
@ -117,8 +137,9 @@ lines : line
|
|||
| 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
|
||||
|
@ -126,85 +147,165 @@ 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"); }
|
||||
;
|
||||
|
||||
|
||||
settings: setting
|
||||
| settings ',' setting
|
||||
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"); }
|
||||
;
|
||||
|
||||
setting : L_OUTPUT { select_mixer_direction(OUTPUT); }
|
||||
dsetting
|
||||
| L_INPUT { select_mixer_direction(INPUT); }
|
||||
dsetting
|
||||
| error { yyerror( "unknown keyword in mixer channel level" ); }
|
||||
m_switch1 : m_switch1_0
|
||||
| m_switch1 ',' m_switch1_0
|
||||
;
|
||||
|
||||
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_switch1_0 : boolean { mixer_switch1_value($1); }
|
||||
| error { yyerror("an unknown keyword in the Switch1 element level"); }
|
||||
;
|
||||
|
||||
vsettings: vsetting
|
||||
| vsettings vsetting
|
||||
m_switch2 : m_switch2_0
|
||||
| m_switch2 ',' m_switch2_0
|
||||
;
|
||||
|
||||
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_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"); }
|
||||
;
|
||||
|
||||
m_accu3 : m_accu3_0
|
||||
| m_accu3 ',' m_accu3_0
|
||||
;
|
||||
|
||||
m_accu3_0 : integer { mixer_accu3_value($1); }
|
||||
| error { yyerror("an unknown keyword in the Accu3 element level"); }
|
||||
;
|
||||
|
||||
m_mux1 : m_mux1_0
|
||||
| m_mux1 ',' m_mux1_0
|
||||
;
|
||||
|
||||
m_mux1_0 : L_ELEMENT '(' string
|
||||
',' integer ','
|
||||
integer ')' { mixer_mux1_value($3, $5, $7); }
|
||||
| error { yyerror("an unknown keyword in the Mux1 element level"); }
|
||||
;
|
||||
|
||||
m_tone_control1 : m_tone_control1_0
|
||||
| m_tone_control1 ',' m_tone_control1_0
|
||||
;
|
||||
|
||||
m_tone_control1_0 : L_SW '=' boolean { mixer_tone_control1_value(SND_MIXER_TC1_SW, $3); }
|
||||
| L_BASS '=' integer { mixer_tone_control1_value(SND_MIXER_TC1_BASS, $3); }
|
||||
| L_TREBLE '=' integer { mixer_tone_control1_value(SND_MIXER_TC1_TREBLE, $3); }
|
||||
| error { yyerror("an unknown keyword in the ToneControl1 element level"); }
|
||||
;
|
||||
|
||||
|
||||
pcms : pcm
|
||||
| pcms pcm
|
||||
;
|
||||
|
||||
pcm : L_PLAYBACK '{' playbacks '}'
|
||||
| L_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
|
||||
|
@ -219,31 +320,34 @@ inputs : input
|
|||
| 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 ); }
|
||||
|
@ -258,24 +362,21 @@ 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" ); }
|
||||
;
|
||||
|
||||
%%
|
||||
|
@ -293,7 +394,12 @@ static void yyerror(char *string,...)
|
|||
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;
|
||||
|
||||
|
@ -301,17 +407,24 @@ static void select_soundcard(char *name)
|
|||
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;
|
||||
|
||||
|
@ -319,17 +432,24 @@ static void select_mixer(char *name)
|
|||
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;
|
||||
|
||||
|
@ -337,17 +457,24 @@ static void select_pcm(char *name)
|
|||
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;
|
||||
|
||||
|
@ -355,185 +482,342 @@ static void select_rawmidi(char *name)
|
|||
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);
|
||||
free(name);
|
||||
}
|
||||
|
||||
static void select_mixer_channel(char *name)
|
||||
{
|
||||
struct mixer_channel *channel;
|
||||
|
||||
if (!name) {
|
||||
Xchannel = NULL;
|
||||
Xrawmidi = (struct rawmidi *)malloc(sizeof(struct rawmidi));
|
||||
if (!Xrawmidi) {
|
||||
free(name);
|
||||
error_nomem();
|
||||
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);
|
||||
return;
|
||||
}
|
||||
yyerror("Cannot find mixer channel '%s'...", name);
|
||||
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_direction(int direction)
|
||||
static void build_mixer_element(char *name, int index, int etype)
|
||||
{
|
||||
Xchannel->direction = direction;
|
||||
}
|
||||
struct mixer_element *element;
|
||||
|
||||
static void select_mixer_voice(int voice)
|
||||
{
|
||||
Xchannel->voice = voice;
|
||||
}
|
||||
|
||||
static void set_mixer_volume(int volume)
|
||||
{
|
||||
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;
|
||||
if (!name) {
|
||||
Xelement = NULL;
|
||||
return;
|
||||
}
|
||||
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 = (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 set_mixer_flags(int flags)
|
||||
static void mixer_type_check(int type)
|
||||
{
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (Xelement->element.eid.type != type)
|
||||
yyerror("The element has got the unexpected data type.");
|
||||
}
|
||||
|
||||
static void select_mixer_channel_end(void)
|
||||
static void mixer_switch1(int end)
|
||||
{
|
||||
mixer_type_check(SND_MIXER_ETYPE_SWITCH1);
|
||||
}
|
||||
|
||||
static void find_switch(int xtype, struct ctl_switch *first, char *name, char *err)
|
||||
static void mixer_switch1_value(int val)
|
||||
{
|
||||
unsigned int *ptr;
|
||||
|
||||
if (Xelement->element.data.switch1.sw_size <= Xelement->element.data.switch1.sw) {
|
||||
Xelement->element.data.switch1.sw_size += 32;
|
||||
ptr = (unsigned int *)realloc(Xelement->element.data.switch1.psw, ((Xelement->element.data.switch1.sw_size + 31) / 32) * sizeof(unsigned int));
|
||||
if (ptr == NULL) {
|
||||
error_nomem();
|
||||
return;
|
||||
}
|
||||
Xelement->element.data.switch1.psw = ptr;
|
||||
}
|
||||
snd_mixer_set_bit(Xelement->element.data.switch1.psw, Xelement->element.data.switch1.sw++, val ? 1 : 0);
|
||||
}
|
||||
|
||||
static void mixer_switch2(int end)
|
||||
{
|
||||
mixer_type_check(SND_MIXER_ETYPE_SWITCH2);
|
||||
}
|
||||
|
||||
static void mixer_switch2_value(int val)
|
||||
{
|
||||
Xelement->element.data.switch2.sw = val ? 1 : 0;
|
||||
}
|
||||
|
||||
static void mixer_switch3(int end)
|
||||
{
|
||||
mixer_type_check(SND_MIXER_ETYPE_SWITCH3);
|
||||
}
|
||||
|
||||
static void mixer_switch3_value(int val)
|
||||
{
|
||||
unsigned int *ptr;
|
||||
|
||||
if (Xelement->element.data.switch3.rsw_size <= Xelement->element.data.switch3.rsw) {
|
||||
Xelement->element.data.switch3.rsw_size += 32;
|
||||
ptr = (unsigned int *)realloc(Xelement->element.data.switch1.psw, ((Xelement->element.data.switch3.rsw_size + 31) / 32) * sizeof(unsigned int));
|
||||
if (ptr == NULL) {
|
||||
error_nomem();
|
||||
return;
|
||||
}
|
||||
Xelement->element.data.switch3.prsw = ptr;
|
||||
}
|
||||
snd_mixer_set_bit(Xelement->element.data.switch3.prsw, Xelement->element.data.switch3.rsw++, val ? 1 : 0);
|
||||
}
|
||||
|
||||
static void mixer_volume1(int end)
|
||||
{
|
||||
mixer_type_check(SND_MIXER_ETYPE_VOLUME1);
|
||||
}
|
||||
|
||||
static void mixer_volume1_value(int val)
|
||||
{
|
||||
int *ptr;
|
||||
|
||||
if (Xelement->element.data.volume1.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;
|
||||
}
|
||||
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 mixer_accu3_value(int val)
|
||||
{
|
||||
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;
|
||||
}
|
||||
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 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 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;
|
||||
}
|
||||
yyerror("Cannot find %s switch '%s'...", err, name);
|
||||
bzero(Xswitch, sizeof(*Xswitch));
|
||||
for (sw = *first; sw && sw->next; sw = sw->next);
|
||||
if (sw) {
|
||||
sw->next = Xswitch;
|
||||
} else {
|
||||
*first = Xswitch;
|
||||
}
|
||||
strncpy(Xswitch->s.name, name, sizeof(Xswitch->s.name));
|
||||
free(name);
|
||||
}
|
||||
|
||||
static void 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_bytearray(struct bytearray val)
|
||||
{
|
||||
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)
|
||||
{
|
||||
snd_switch_t *sw = Xswitch;
|
||||
|
||||
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,
|
||||
|
@ -542,11 +826,8 @@ static void set_switch_iec958ocs_begin(int end)
|
|||
#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 */
|
||||
|
|
492
alsactl/merge.c
Normal file
492
alsactl/merge.c
Normal file
|
@ -0,0 +1,492 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
707
alsactl/setup.c
707
alsactl/setup.c
|
@ -31,6 +31,32 @@ extern int linecount;
|
|||
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
|
||||
|
@ -47,12 +73,14 @@ static void soundcard_ctl_switch_free(struct ctl_switch *first)
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -62,7 +90,7 @@ static void soundcard_mixer_free1(struct mixer *mixer)
|
|||
{
|
||||
if (!mixer)
|
||||
return;
|
||||
soundcard_mixer_channel_free(mixer->channels);
|
||||
soundcard_mixer_element_free(mixer->elements);
|
||||
soundcard_ctl_switch_free(mixer->switches);
|
||||
free(mixer);
|
||||
}
|
||||
|
@ -173,6 +201,7 @@ void soundcard_setup_init(void)
|
|||
void soundcard_setup_done(void)
|
||||
{
|
||||
soundcard_free(soundcards);
|
||||
soundcard_free(rsoundcards);
|
||||
soundcards = NULL;
|
||||
}
|
||||
|
||||
|
@ -294,13 +323,12 @@ static int determine_switches(void *handle, struct ctl_switch **csw, int interfa
|
|||
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;
|
||||
|
||||
|
@ -369,73 +397,15 @@ int soundcard_setup_collect(int cardno)
|
|||
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);
|
||||
}
|
||||
/* --- */
|
||||
|
@ -450,7 +420,7 @@ int soundcard_setup_collect(int cardno)
|
|||
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)) {
|
||||
|
@ -480,7 +450,7 @@ int soundcard_setup_collect(int cardno)
|
|||
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)) {
|
||||
|
@ -503,6 +473,133 @@ int soundcard_setup_collect(int cardno)
|
|||
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);
|
||||
|
@ -570,9 +667,9 @@ static void soundcard_setup_write_switch(FILE * out, const char *space, int inte
|
|||
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++) {
|
||||
|
@ -589,36 +686,36 @@ static void soundcard_setup_write_switch(FILE * out, const char *space, int inte
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
@ -627,15 +724,15 @@ static void soundcard_setup_write_switch(FILE * out, const char *space, int inte
|
|||
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)
|
||||
|
@ -648,112 +745,183 @@ static void soundcard_setup_write_switches(FILE *out, const char *space, int int
|
|||
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);
|
||||
}
|
||||
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);
|
||||
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");
|
||||
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, " 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");
|
||||
|
@ -763,8 +931,8 @@ int soundcard_setup_write(const char *cfgfile)
|
|||
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) {
|
||||
|
@ -799,121 +967,80 @@ int soundcard_setup_write(const char *cfgfile)
|
|||
}
|
||||
fprintf(out, " }\n");
|
||||
}
|
||||
fprintf(out, "}\n%s", first->next ? "\n" : "");
|
||||
fprintf(out, "}\n%s", cardno < 0 && 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;
|
||||
}
|
||||
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));
|
||||
/* 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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -1,964 +1,6 @@
|
|||
/* 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)
|
||||
void main(void)
|
||||
{
|
||||
dc_fg[n] = f;
|
||||
dc_attrib[n] = a;
|
||||
dc_char[n] = c;
|
||||
if (n > 0)
|
||||
init_pair(n, dc_fg[n] & 0xf, b & 0x0f);
|
||||
printf("TODO\n");
|
||||
}
|
||||
|
||||
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, "");
|
||||
};
|
||||
|
|
964
alsamixer/alsamixer_abramo.c
Normal file
964
alsamixer/alsamixer_abramo.c
Normal file
|
@ -0,0 +1,964 @@
|
|||
/* 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, "");
|
||||
};
|
|
@ -1,8 +1,8 @@
|
|||
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
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
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
|
270
amixer/amain.cpp
270
amixer/amain.cpp
|
@ -1,270 +0,0 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
1259
amixer/amixer.c
Normal file
1259
amixer/amixer.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,128 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* 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? */
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
/*
|
||||
* 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
|
||||
|
@ -16,60 +18,4 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#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"
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
typedef int int32;
|
Loading…
Reference in a new issue