int change;
snd_mixer_channel_info_t i;
snd_mixer_channel_t c;
+ snd_mixer_channel_t cr;
struct mixer_channel *next;
};
"{"|"}" return yytext[0];
"("|")" return yytext[0];
+"["|"]" return yytext[0];
")"[ \t]*"{" return L_DOUBLE1;
"," return yytext[0];
\'[^\']*\' { yytext[ strlen( yytext ) - 1 ] = 0;
yylval.s_value = strdup( &yytext[ 1 ] );
return L_STRING; }
-[a-z0-9/\~@-_\+=:\.]+ { yylval.s_value = strdup( yytext );
+[a-z0-9/\~@-Za-z_\+=:\.]+ { yylval.s_value = strdup( yytext );
return L_STRING; }
-$[a-z0-9/\~@-_\+=:\.]+ { yylval.s_value = strdup( getenv( &yytext[ 1 ] ) );
+$[a-z0-9/\~@-Za-z_\+=:\.]+ { yylval.s_value = strdup( getenv( &yytext[ 1 ] ) );
return L_STRING; }
/* comments & whitespaces */
static void select_mixer_channel(char *name);
static void set_mixer_channel(int left, int right);
+static void set_mixer_channel_record(int left, int right);
static void set_mixer_channel_flags(unsigned int mask, unsigned int flags);
static void set_mixer_channel_end(void);
;
xmchl : L_INTEGER { set_mixer_channel( $1, -1 ); }
+ | '[' L_INTEGER ']' { set_mixer_channel_record( $2, -1 ); }
| L_MUTE { set_mixer_channel_flags( SND_MIXER_FLG_MUTE_LEFT, SND_MIXER_FLG_MUTE_LEFT ); }
| L_RECORD { set_mixer_channel_flags( SND_MIXER_FLG_RECORD_LEFT, SND_MIXER_FLG_RECORD_LEFT ); }
| L_SWOUT { set_mixer_channel_flags( SND_MIXER_FLG_LTOR_OUT, SND_MIXER_FLG_LTOR_OUT ); }
;
xmchr : L_INTEGER { set_mixer_channel( -1, $1 ); }
+ | '[' L_INTEGER ']' { set_mixer_channel_record( -1, $2 ); }
| L_MUTE { set_mixer_channel_flags( SND_MIXER_FLG_MUTE_RIGHT, SND_MIXER_FLG_MUTE_RIGHT ); }
| L_RECORD { set_mixer_channel_flags( SND_MIXER_FLG_RECORD_RIGHT, SND_MIXER_FLG_RECORD_RIGHT ); }
| L_SWOUT { set_mixer_channel_flags( SND_MIXER_FLG_RTOL_OUT, SND_MIXER_FLG_RTOL_OUT ); }
;
xmch : L_INTEGER { set_mixer_channel( $1, $1 ); }
+ | '[' L_INTEGER ']' { set_mixer_channel_record( $2, $2 ); }
| L_MUTE { set_mixer_channel_flags( SND_MIXER_FLG_MUTE, SND_MIXER_FLG_MUTE ); }
| L_RECORD { set_mixer_channel_flags( SND_MIXER_FLG_RECORD, SND_MIXER_FLG_RECORD ); }
| error { yyerror( "unknown keyword in mono channel section..." ); }
}
}
+static void set_mixer_channel_record(int left, int right)
+{
+ if (left >= 0) {
+ if (Xmixerchannel->i.min > left || Xmixerchannel->i.max < left)
+ yyerror("Value out of range (%i-%i)...", Xmixerchannel->i.min, Xmixerchannel->i.max);
+ if (Xmixerchannel->cr.left != left)
+ Xmixerchannel->change = 1;
+ Xmixerchannel->cr.left = left;
+ }
+ if (right >= 0) {
+ if (Xmixerchannel->i.min > right || Xmixerchannel->i.max < right)
+ yyerror("Value out of range (%i-%i)...", Xmixerchannel->i.min, Xmixerchannel->i.max);
+ if (Xmixerchannel->cr.right != right)
+ Xmixerchannel->change = 1;
+ Xmixerchannel->cr.right = right;
+ }
+}
+
static void set_mixer_channel_flags(unsigned int mask, unsigned int flags)
{
Xmixerchannelflags &= ~mask;
error("MIXER channel read error (%s) - skipping", snd_strerror(err));
break;
}
+ if ((mixerchannel->i.caps & SND_MIXER_CINFO_CAP_RECORDVOLUME) &&
+ (err = snd_mixer_channel_record_read(mhandle, idx, &mixerchannel->cr)) < 0) {
+ free(mixerchannel);
+ error("MIXER channel record read error (%s) - skipping", snd_strerror(err));
+ break;
+ }
if (!mixerchannelprev) {
mixer->channels = mixerchannel;
} else {
}
-static void soundcard_setup_write_mixer_channel(FILE * out, snd_mixer_channel_info_t * info, snd_mixer_channel_t * channel)
+static void soundcard_setup_write_mixer_channel(FILE * out, snd_mixer_channel_info_t * info, snd_mixer_channel_t * channel, snd_mixer_channel_t * record_channel)
{
fprintf(out, " ; Capabilities:%s%s%s%s%s%s%s%s%s%s%s%s%s.\n",
info->caps & SND_MIXER_CINFO_CAP_RECORD ? " record" : "",
info->caps & SND_MIXER_CINFO_CAP_SWITCH_OUT ? " switch-out" : "",
info->caps & SND_MIXER_CINFO_CAP_LTOR_IN ? " ltor-in" : "",
info->caps & SND_MIXER_CINFO_CAP_RTOL_IN ? " rtol-in" : "",
- info->caps & SND_MIXER_CINFO_CAP_RECORDBYMUTE ? " record-by-mute" : "");
+ info->caps & SND_MIXER_CINFO_CAP_RECORDVOLUME ? " record-volume" : "");
fprintf(out, " ; Accepted channel range is from %i to %i.\n", info->min, info->max);
fprintf(out, " channel( \"%s\", ", info->name);
if (info->caps & SND_MIXER_CINFO_CAP_STEREO) {
- fprintf(out, "stereo( %i%s%s%s%s, %i%s%s%s%s )",
+ char bufl[16] = "";
+ char bufr[16] = "";
+ if (info->caps & SND_MIXER_CINFO_CAP_RECORDVOLUME) {
+ sprintf(bufl, " [%i]", record_channel->left);
+ sprintf(bufr, " [%i]", record_channel->right);
+ }
+ fprintf(out, "stereo( %i%s%s%s%s%s, %i%s%s%s%s%s )",
channel->left,
- channel->flags & SND_MIXER_FLG_MUTE_LEFT ? " mute" : "",
+ channel->flags & SND_MIXER_FLG_MUTE_LEFT ? " mute" : "",
channel->flags & SND_MIXER_FLG_RECORD_LEFT ? " record" : "",
- channel->flags & SND_MIXER_FLG_LTOR_OUT ? " swout" : "",
- channel->flags & SND_MIXER_FLG_LTOR_IN ? " swin" : "",
+ bufl,
+ channel->flags & SND_MIXER_FLG_LTOR_OUT ? " swout" : "",
+ channel->flags & SND_MIXER_FLG_LTOR_IN ? " swin" : "",
channel->right,
- channel->flags & SND_MIXER_FLG_MUTE_RIGHT ? " mute" : "",
+ channel->flags & SND_MIXER_FLG_MUTE_RIGHT ? " mute" : "",
channel->flags & SND_MIXER_FLG_RECORD_RIGHT ? " record" : "",
- channel->flags & SND_MIXER_FLG_RTOL_OUT ? " swout" : "",
- channel->flags & SND_MIXER_FLG_RTOL_IN ? " swin" : ""
+ bufr,
+ channel->flags & SND_MIXER_FLG_RTOL_OUT ? " swout" : "",
+ channel->flags & SND_MIXER_FLG_RTOL_IN ? " swin" : ""
);
} else {
- fprintf(out, "mono( %i%s%s )",
+ char buf[16] = "";
+ if (info->caps & SND_MIXER_CINFO_CAP_RECORDVOLUME)
+ sprintf(buf, " [%i]", (record_channel->left+record_channel->right) /2);
+ fprintf(out, "mono( %i%s%s%s )",
(channel->left + channel->right) / 2,
- channel->flags & SND_MIXER_FLG_MUTE ? " mute" : "",
- channel->flags & SND_MIXER_FLG_RECORD ? " record" : ""
+ channel->flags & SND_MIXER_FLG_MUTE ? " mute" : "",
+ channel->flags & SND_MIXER_FLG_RECORD ? " record" : "",
+ buf
);
}
fprintf(out, " )\n");
for (mixer = first->mixers; mixer; mixer = mixer->next) {
fprintf(out, " mixer( \"%s\" ) {\n", mixer->info.name);
for (mixerchannel = mixer->channels; mixerchannel; mixerchannel = mixerchannel->next)
- soundcard_setup_write_mixer_channel(out, &mixerchannel->i, &mixerchannel->c);
+ soundcard_setup_write_mixer_channel(out, &mixerchannel->i, &mixerchannel->c, &mixerchannel->cr);
for (mixersw = mixer->switches; mixersw; mixersw = mixersw->next)
soundcard_setup_write_switch(out, SND_INTERFACE_MIXER, mixersw->s.name, mixersw->s.type, mixersw->s.low, mixersw->s.high, (void *) (&mixersw->s.value));
fprintf(out, " }\n");
if (!soundcard_open_mix(&mixhandle, soundcard, mixer)) {
if ((err = snd_mixer_channel_write(mixhandle, channel->no, &channel->c)) < 0)
error("Mixer channel '%s' write error: %s", channel->i.name, snd_strerror(err));
+ if ((channel->i.caps & SND_MIXER_CINFO_CAP_RECORDVOLUME) &&
+ (err = snd_mixer_channel_record_write(mixhandle, channel->no, &channel->cr)) < 0)
+ error("Mixer channel '%s' record write error: %s", channel->i.name, snd_strerror(err));
}
if (mixhandle) {
snd_mixer_close(mixhandle);
removed from the sources used for recording. This only works for valid
input channels, of course.
+\fIR\fP toggle display of playback or record mixer.
+
\fIL\fP re-draws the screen.
\fITAB\fP toggles the mode for volume display. See description for the
static int mixer_focus_channel = 0;
static int mixer_exact = 0;
+static int mixer_record_volumes = 0;
+
static int mixer_lvolume_delta = 0;
static int mixer_rvolume_delta = 0;
static int mixer_balance_volumes = 0;
{0};
snd_mixer_channel_t cdata =
{0};
+ snd_mixer_channel_t crdata =
+ {0};
int vleft, vright;
int x, y, i;
+ int channel_record_volume;
/* set specified EXACT mode
*/
*/
if (snd_mixer_channel_info(mixer_handle, channel_index, &cinfo) < 0)
mixer_abort(ERR_FCN, "snd_mixer_channel_info");
+ channel_record_volume = (cinfo.caps & SND_MIXER_CINFO_CAP_RECORDVOLUME);
/* set new channel values
*/
mixer_route_rtol_in || mixer_route_ltor_in)) {
if (snd_mixer_channel_read(mixer_handle, channel_index, &cdata) < 0)
mixer_abort(ERR_FCN, "snd_mixer_channel_read");
+ if (mixer_record_volumes && channel_record_volume &&
+ snd_mixer_channel_record_read(mixer_handle, channel_index, &crdata) < 0)
+ mixer_abort(ERR_FCN, "snd_mixer_channel_record_read");
cdata.flags &= ~SND_MIXER_FLG_DECIBEL;
- cdata.left = CLAMP(cdata.left + mixer_lvolume_delta, cinfo.min, cinfo.max);
- cdata.right = CLAMP(cdata.right + mixer_rvolume_delta, cinfo.min, cinfo.max);
- mixer_lvolume_delta = mixer_rvolume_delta = 0;
+ if (mixer_lvolume_delta) {
+ if (mixer_record_volumes) {
+ if (channel_record_volume)
+ crdata.left = CLAMP(crdata.left + mixer_lvolume_delta, cinfo.min, cinfo.max);
+ }
+ else
+ cdata.left = CLAMP(cdata.left + mixer_lvolume_delta, cinfo.min, cinfo.max);
+ mixer_lvolume_delta = 0;
+ }
+ if (mixer_rvolume_delta) {
+ if (mixer_record_volumes) {
+ if (channel_record_volume)
+ crdata.right = CLAMP(crdata.right + mixer_rvolume_delta, cinfo.min, cinfo.max);
+ }
+ else
+ cdata.right = CLAMP(cdata.right + mixer_rvolume_delta, cinfo.min, cinfo.max);
+ mixer_rvolume_delta = 0;
+ }
if (mixer_balance_volumes) {
- cdata.left = (cdata.left + cdata.right) / 2;
- cdata.right = cdata.left;
+ if (mixer_record_volumes) {
+ if (channel_record_volume) {
+ crdata.left = (crdata.left + crdata.right) / 2;
+ crdata.right = crdata.left;
+ }
+ }
+ else {
+ cdata.left = (cdata.left + cdata.right) / 2;
+ cdata.right = cdata.left;
+ }
mixer_balance_volumes = 0;
}
if (mixer_toggle_mute_left) {
if (snd_mixer_channel_write(mixer_handle, channel_index, &cdata) < 0)
mixer_abort(ERR_FCN, "snd_mixer_channel_write");
+ if (mixer_record_volumes && channel_record_volume &&
+ snd_mixer_channel_record_write(mixer_handle, channel_index, &crdata) < 0)
+ mixer_abort(ERR_FCN, "snd_mixer_channel_record_write");
}
/* first, read values for the numbers to be displayed in
* specified EXACT mode
*/
if (snd_mixer_channel_read(mixer_handle, channel_index, &cdata) < 0)
mixer_abort(ERR_FCN, "snd_mixer_ioctl_channel_read");
- vleft = cdata.left;
- vright = cdata.right;
+ if (mixer_record_volumes) {
+ if (channel_record_volume) {
+ if (snd_mixer_channel_record_read(mixer_handle, channel_index, &crdata) < 0)
+ mixer_abort(ERR_FCN, "snd_mixer_channel_record_read");
+ vleft = crdata.left;
+ vright = crdata.right;
+ }
+ else
+ vleft = vright = 0;
+ }
+ else {
+ vleft = cdata.left;
+ vright = cdata.right;
+ }
/* then, always use percentage values for the bars. if we don't do
* this, we will see aliasing effects on specific circumstances.
mixer_abort(ERR_FCN, "snd_mixer_exact");
if (snd_mixer_channel_read(mixer_handle, channel_index, &cdata) < 0)
mixer_abort(ERR_FCN, "snd_mixer_channel_read");
+ if (mixer_record_volumes && channel_record_volume &&
+ snd_mixer_channel_record_read(mixer_handle, channel_index, &crdata) < 0)
+ mixer_abort(ERR_FCN, "snd_mixer_channel_record_read");
}
/* get channel bar position
*/
dc = DC_CBAR_FULL_2;
else
dc = DC_CBAR_FULL_1;
- mvaddch(y, x + 3, mixer_dc(cdata.left > i * 100 / mixer_cbar_height ? dc : DC_CBAR_EMPTY));
- mvaddch(y, x + 4, mixer_dc(cdata.right > i * 100 / mixer_cbar_height ? dc : DC_CBAR_EMPTY));
+ 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--;
}
if (strlen(string) > max_len)
string[max_len] = 0;
mvaddstr(2, 2 + 6, string);
+ if (mixer_record_volumes)
+ mvaddstr(3, 2, "Record mixer");
+ else
+ mvaddstr(3, 2, " ");
}
static void mixer_init(void)
break;
case 'm':
case 'M':
+ mixer_record_volumes = 0;
mixer_toggle_mute_left = 1;
mixer_toggle_mute_right = 1;
break;
break;
case '<':
case ',':
+ mixer_record_volumes = 0;
mixer_toggle_mute_left = 1;
break;
case '>':
case '.':
+ mixer_record_volumes = 0;
mixer_toggle_mute_right = 1;
break;
case 'R':
case 'r':
+ mixer_record_volumes = !mixer_record_volumes;
+ break;
case 'L':
case 'l':
mixer_clear();
mixer_toggle_rec_right = 1;
break;
case '1':
+ mixer_record_volumes = 0;
mixer_route_rtol_in = 1;
break;
case '2':
+ mixer_record_volumes = 0;
mixer_route_ltor_in = 1;
break;
}