diff --git a/wmamixer.c b/wmamixer.c index 83a440e..0b35d80 100644 --- a/wmamixer.c +++ b/wmamixer.c @@ -11,7 +11,7 @@ #include "wmamixer.h" // global mixer struct -struct Mixer *mixer_ctrl; +struct Mixer *mix; int main(int argc, char **argv) { int i; @@ -32,24 +32,6 @@ int main(int argc, char **argv) { scanArgs(argc, argv); initXWin(argc, argv); - xpmattr.numsymbols = 4; - xpmattr.colorsymbols = xpmcsym; - xpmattr.exactColors = false; - xpmattr.closeness = 40000; - xpmattr.valuemask = XpmColorSymbols | XpmExactColors | XpmCloseness; - XpmCreatePixmapFromData(d_display, w_root, wmsmixer_xpm, &pm_main, - &pm_mask, &xpmattr); - XpmCreatePixmapFromData(d_display, w_root, tile_xpm, &pm_tile, NULL, - &xpmattr); - XpmCreatePixmapFromData(d_display, w_root, icons_xpm, &pm_icon, NULL, - &xpmattr); - XpmCreatePixmapFromData(d_display, w_root, digits_xpm, &pm_digits, NULL, - &xpmattr); - XpmCreatePixmapFromData(d_display, w_root, chars_xpm, &pm_chars, NULL, - &xpmattr); - pm_disp = XCreatePixmap(d_display, w_root, 64, 64, DefaultDepth(d_display, - DefaultScreen(d_display))); - gcm = GCGraphicsExposures; gcv.graphics_exposures = false; gc_gc = XCreateGC(d_display, w_root, gcm, &gcv); @@ -59,6 +41,24 @@ int main(int argc, char **argv) { color[2] = mixColor(ledcolor, 60, backcolor, 40); color[3] = mixColor(ledcolor, 25, backcolor, 75); + xpmattr.numsymbols = 4; + xpmattr.colorsymbols = xpmcsym; + xpmattr.exactColors = false; + xpmattr.closeness = 40000; + xpmattr.valuemask = XpmColorSymbols | XpmExactColors | XpmCloseness; + XpmCreatePixmapFromData(d_display, w_root, wmsmixer_xpm, &pm_main, + &pm_mask, &xpmattr); + XpmCreatePixmapFromData(d_display, w_root, tile_xpm, &pm_tile, NULL, + &xpmattr); + XpmCreatePixmapFromData(d_display, w_root, icons_xpm, &pm_icon, NULL, + &xpmattr); + XpmCreatePixmapFromData(d_display, w_root, digits_xpm, &pm_digits, NULL, + &xpmattr); + XpmCreatePixmapFromData(d_display, w_root, chars_xpm, &pm_chars, NULL, + &xpmattr); + pm_disp = XCreatePixmap(d_display, w_root, 64, 64, DefaultDepth(d_display, + DefaultScreen(d_display))); + if (wmaker || ushape || astep) { XShapeCombineMask(d_display, w_activewin, ShapeBounding, winsize/2-32, winsize/2-32, pm_mask, ShapeSet); @@ -70,26 +70,12 @@ int main(int argc, char **argv) { XCopyArea(d_display, pm_main, pm_disp, gc_gc, 0, 0, 64, 64, 0, 0); XSetClipMask(d_display, gc_gc, None); - mixer_ctrl = Mixer_create(mixer_device); - - if (mixer_ctrl->openOK != 0) { - fprintf(stderr, "%s : Unable to open mixer device '%s'.\n", NAME, - mixer_device); - } else { - for (i=0; i devices_no; i++) { - if (i > 24) { - fprintf(stderr,"%s : Sorry, can only use channels 0-24\n", NAME); - break; - } - channel[channels] = i; - channels++; - } - } + mix = Mixer_create(card); readFile(); - if (channels==0) - fprintf(stderr,"%s : Sorry, no supported channels found.\n", NAME); + if (mix->devices_no == 0) + fprintf(stderr,"%s: Sorry, no supported channels found.\n", NAME); else { checkVol(true); @@ -129,8 +115,8 @@ int main(int argc, char **argv) { else curchannel--; if (curchannel < 0) - curchannel = channels - 1; - if (curchannel >= channels) + curchannel = mix->devices_no - 1; + if (curchannel >= mix->devices_no) curchannel = 0; checkVol(true); rpttimer = 0; @@ -145,7 +131,7 @@ int main(int argc, char **argv) { drawVolLevel(); repaint(); } - // printf("%c", text_counter); + // printf("%c", text_counter); } XFlush(d_display); @@ -163,19 +149,290 @@ int main(int argc, char **argv) { XFreePixmap(d_display, pm_digits); XFreePixmap(d_display, pm_chars); freeXWin(); - Mixer_destroy(mixer_ctrl); + Mixer_destroy(mix); return 0; } - /* Mixer struct support functions */ -struct Mixer *Mixer_create(char *device) { - struct Mixer *mixer_ctrl = malloc(sizeof(struct Mixer)); - assert(mixer_ctrl != NULL); - mixer_ctrl->openOK = 0; - mixer_ctrl->devices_no = 0; - mixer_ctrl->devices_no = 0; - return mixer_ctrl; +struct Mixer *Mixer_create(char *devicename) { + struct Mixer *mixer = malloc(sizeof(struct Mixer)); + int err; + const char *name; + slideCaptureMono capabilities; + + snd_mixer_selem_id_t *sid; + snd_mixer_elem_t *elem; + snd_mixer_selem_id_alloca(&sid); + + assert(mixer != NULL); + mixer->devices_no = 0; + + if ((err = snd_mixer_open(&mixer->handle, 0)) < 0) { + fprintf(stderr, "Mixer %s open error: %s", card, snd_strerror(err)); + exit(err); + } + + if (smixer_level == 0 && + (err = snd_mixer_attach(mixer->handle, card)) < 0) { + fprintf(stderr, "Mixer attach %s error: %s", card, snd_strerror(err)); + snd_mixer_close(mixer->handle); + exit(err); + } + + if ((err = snd_mixer_selem_register(mixer->handle, + smixer_level > 0 ? &smixer_options : NULL, NULL)) < 0) { + fprintf(stderr, "Mixer register error: %s", snd_strerror(err)); + snd_mixer_close(mixer->handle); + exit(err); + } + + err = snd_mixer_load(mixer->handle); + + if (err < 0) { + fprintf(stderr, "Mixer %s load error: %s", card, snd_strerror(err)); + snd_mixer_close(mixer->handle); + exit(err); + } + for (elem = snd_mixer_first_elem(mixer->handle); elem; + elem = snd_mixer_elem_next(elem)) { + snd_mixer_selem_get_id(elem, sid); + + if (!snd_mixer_selem_is_active(elem)) + continue; + + capabilities = Mixer_getcapabilities(elem); + + if (!capabilities.isvolume) + continue; + name = snd_mixer_selem_id_get_name(sid); + printf("DEBUG: capabilities cap: %d\n", capabilities.capture); + selems[mixer->devices_no] = malloc(sizeof(struct Selem)); + selems[mixer->devices_no]->elem = elem; + selems[mixer->devices_no]->capture = capabilities.capture; + Mixer_set_limits(elem, selems[mixer->devices_no]); + Mixer_set_selem_props(selems[mixer->devices_no], name); + mixer->devices_no++; + printf("DEBUG: Simple mixer control '%s',%i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid)); + if (mixer->devices_no == 32) { + // stop here. This is ridiculous anyway + break; + } + } + return mixer; +} + +/* Guess and return short name for the mixer simple element */ +void Mixer_set_selem_props(struct Selem *selem, const char *name) { + const char *pcm = "PCM", + *mic = "Mic", + *cap = "Capture", + *boost = "Boost", + *line = "Line"; + + snd_mixer_selem_channel_id_t chn; + char variable[4]; + int idx; + + // Get the name. Simple match. + if (strcmp("Master", name) == 0) { + selem->name = "mstr"; + } else if (strstr(pcm, name)) { + selem->iconIndex = 1; + if (strcmp(pcm, name) == 0) { + selem->name = "pcm "; + } else { + sprintf(variable, "pcm%d", namesCount.pcm); + selem->name = variable; + namesCount.pcm++; + } + } else if (strstr("Headphone", name)) { + selem->name = "hdph"; + selem->iconIndex = 8; + } else if (strstr("Beep", name)) { + selem->name = "beep"; + selem->iconIndex = 7; + } else if (strstr("Digital", name)) { + selem->iconIndex = selem->capture ? 3 : 6; + selem->name = "digt"; + } else if (strstr(mic, name)) { + if (strcmp(mic, name) == 0) { + selem->name = "mic "; + } else { + if (strstr(boost, name)) { + sprintf(variable, "mib%d", namesCount.micb); + namesCount.micb++; + } else { + sprintf(variable, "mib%d", namesCount.mic); + namesCount.mic++; + } + selem->name = variable; + } + selem->iconIndex = 4; + } else if (strstr(line, name)) { + if (strcmp(line, name) == 0) { + selem->name = "line"; + } else { + if (strstr(boost, name)) { + sprintf(variable, "lnb%d", namesCount.lineb); + namesCount.lineb++; + } else { + sprintf(variable, "lin%d", namesCount.line); + namesCount.line++; + } + selem->name = variable; + } + selem->iconIndex = 5; + } else if (strstr(cap, name)) { + if (strcmp(cap, name) == 0) { + selem->name = "cap "; + } else { + sprintf(variable, "cap%d", namesCount.capt); + selem->name = variable; + namesCount.capt++; + } + selem->iconIndex = 3; + } else { + /* defaults */ + sprintf(variable, "vol%d", namesCount.vol); + selem->name = variable; + namesCount.pcm++; + selem->iconIndex = 6; + } + + + if (snd_mixer_selem_has_playback_volume(selem->elem)) { + if (snd_mixer_selem_is_playback_mono(selem->elem)) { + printf("DEBUG: playback mono\n"); + selem->stereo = false; + selem->channels[0] = SND_MIXER_SCHN_MONO; + selem->channels[1] = SND_MIXER_SCHN_MONO; + } else { + printf("DEBUG: playback stereo\n"); + idx = 0; + for (chn = 0; chn <= SND_MIXER_SCHN_LAST; chn++){ + if (!snd_mixer_selem_has_playback_channel(selem->elem, chn)) + continue; + selem->channels[idx] = chn; + idx++; + if (idx == 2) + break; + } + } + } + + if (snd_mixer_selem_has_capture_volume(selem->elem)) { + printf("Capture channels: "); + if (snd_mixer_selem_is_capture_mono(selem->elem)) { + printf("DEBUG: playback mono\n"); + selem->stereo = false; + selem->channels[0] = SND_MIXER_SCHN_MONO; + selem->channels[1] = SND_MIXER_SCHN_MONO; + } else { + idx = 0; + for (chn = 0; chn <= SND_MIXER_SCHN_LAST; chn++){ + if (!snd_mixer_selem_has_capture_channel(selem->elem, chn)) + continue; + selem->channels[idx] = chn; + idx++; + if (idx == 2) + break; + } + } + } +} + +slideCaptureMono Mixer_getcapabilities(snd_mixer_elem_t *elem) { + slideCaptureMono retval; + retval.mono = false; + retval.capture = false; + retval.isvolume = false; + + if (snd_mixer_selem_has_common_volume(elem)) { + retval.isvolume = true; + + if (snd_mixer_selem_has_playback_volume_joined(elem) || + snd_mixer_selem_is_playback_mono(elem) ) + retval.mono = true; + } else { + + if (snd_mixer_selem_has_playback_volume(elem)) { + retval.isvolume = true; + if (snd_mixer_selem_has_playback_volume_joined(elem) || + snd_mixer_selem_is_playback_mono(elem)) + retval.mono = true; + } + + if (snd_mixer_selem_has_capture_volume(elem)) { + retval.isvolume = true; + retval.capture = true; + if (snd_mixer_selem_has_capture_volume_joined(elem) || + snd_mixer_selem_is_playback_mono(elem)) + retval.mono = true; + } + } + return retval; +} + +void Mixer_set_limits(snd_mixer_elem_t *elem, struct Selem *selem) { + long min = 0, max = 0; + + if (snd_mixer_selem_has_common_volume(elem)) { + snd_mixer_selem_get_playback_volume_range(elem, &min, &max); + } else { + if (snd_mixer_selem_has_capture_volume(elem)) + snd_mixer_selem_get_capture_volume_range(elem, &min, &max); + if (snd_mixer_selem_has_playback_volume(elem)) + snd_mixer_selem_get_playback_volume_range(elem, &min, &max); + } + + selem->min = min; + selem->max = max; +} + +static int convert_prange(long val, long min, long max) { + long range = max - min; + int tmp; + + if (range == 0) + return 0; + + val -= min; + tmp = rint((double)val/(double)range * 100); + return tmp; +} + +/* +vol_ops = [ + {"has_volume": snd_mixer_selem_has_playback_volume, + "v": [ + [snd_mixer_selem_get_playback_volume_range, + snd_mixer_selem_get_playback_volume, + set_playback_raw_volume], + [snd_mixer_selem_get_playback_dB_range, + snd_mixer_selem_get_playback_dB, + set_playback_dB], + [get_mapped_volume_range, + get_playback_mapped_volume, + set_playback_mapped_volume]] + }, + // capt + {...} +] +*/ + +long get_volume(snd_mixer_elem_t *elem, + snd_mixer_selem_channel_id_t chn, + long min, long max, bool capt) { + long raw; + int volume; + + if (!capt) { + snd_mixer_selem_get_playback_volume(elem, chn, &raw); + } else { + snd_mixer_selem_get_capture_volume(elem, chn, &raw); + } + volume = convert_prange(raw, min, max); + return volume; } void Mixer_set_left(int current, int value) { @@ -188,25 +445,25 @@ void Mixer_write_volume(int current) { } int Mixer_read_left(int current) { - return 50; + struct Selem *selem = selems[current]; + return get_volume(selem->elem, selem->channels[0], + selem->min, selem->max, selem->capture); } int Mixer_read_right(int current) { + struct Selem *selem = selems[current]; + return get_volume(selem->elem, selem->channels[1], + selem->min, selem->max, selem->capture); +} + +int Mixer_read_volume(int current, bool read) { return 50; } -int Mixer_read_volume(int channel, bool read) { - return 50; -} - -bool Mixer_get_stereo(int channel) { - return true; -} - -void Mixer_destroy(struct Mixer *mix) { - assert(mix != NULL); - //free(mix->name); - free(mix); +void Mixer_destroy(struct Mixer *mixer) { + assert(mixer != NULL); + snd_mixer_close(mixer->handle); + free(mixer); } void initXWin(int argc, char **argv) @@ -214,7 +471,7 @@ void initXWin(int argc, char **argv) winsize=astep ? ASTEPSIZE : NORMSIZE; if ((d_display=XOpenDisplay(display))==NULL ) { - fprintf(stderr,"%s : Unable to open X display '%s'.\n", NAME, XDisplayName(display)); + fprintf(stderr,"%s: Unable to open X display '%s'.\n", NAME, XDisplayName(display)); exit(1); } _XA_GNUSTEP_WM_FUNC=XInternAtom(d_display, "_GNUSTEP_WM_FUNCTION", false); @@ -228,7 +485,7 @@ void initXWin(int argc, char **argv) shints.y=0; shints.flags=0; bool pos=(XWMGeometry(d_display, DefaultScreen(d_display), position, NULL, 0, &shints, &shints.x, &shints.y, - &shints.width, &shints.height, &shints.win_gravity) & (XValue | YValue)); + &shints.width, &shints.height, &shints.win_gravity) & (XValue | YValue)); shints.min_width=winsize; shints.min_height=winsize; shints.max_width=winsize; @@ -279,18 +536,6 @@ void createWin(Window *win, int x, int y) XSetClassHint(d_display, *win, &classHint); } -unsigned long getColor(char *colorname) -{ - XColor color; - XWindowAttributes winattr; - XGetWindowAttributes(d_display, w_root, &winattr); - color.pixel=0; - XParseColor(d_display, winattr.colormap, colorname, &color); - color.flags=DoRed | DoGreen | DoBlue; - XAllocColor(d_display, winattr.colormap, &color); - return color.pixel; -} - unsigned long mixColor(char *colorname1, int prop1, char *colorname2, int prop2) { XColor color, color1, color2; @@ -309,67 +554,97 @@ unsigned long mixColor(char *colorname1, int prop1, char *colorname2, int prop2) void scanArgs(int argc, char **argv) { int i; + for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { - usage(); + usage(); exit(0); } - if (strcmp(argv[i], "-v")==0 || strcmp(argv[i], "--version")==0) { - fprintf(stderr, "wmsmixer version %s\n", VERSION); - exit(0); + + if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--version") == 0) { + fprintf(stderr, "%s version %s\n", NAME, VERSION); + exit(0); + } + + if (strcmp(argv[i], "-w") == 0) + wmaker = !wmaker; + + if (strcmp(argv[i], "-s") == 0) + ushape = !ushape; + + if (strcmp(argv[i], "-a") == 0) + astep = !astep; + + if (strcmp(argv[i], "-novol") == 0) + no_volume_display = 1; + + if (strcmp(argv[i], "-d") == 0) { + if (i < argc - 1) { + i++; + if (strlen(argv[i]) > 255) { + fprintf(stderr, "%s: Illegal device name.\n", NAME); + exit(1); + } + sprintf(card, "%s", argv[i]); + smixer_options.device = card; + } + continue; + } + + if (strcmp(argv[i], "-l") == 0) { + if ( i < argc - 1) { + i++; + if (strlen(argv[i]) > 255) { + fprintf(stderr, "%s: Illegal color name.\n", NAME); + exit(1); + } + sprintf(ledcolor, "%s", argv[i]); + } + continue; + } + + if (strcmp(argv[i], "-b") == 0) { + if (i < argc - 1) { + i++; + if (strlen(argv[i]) > 255) { + fprintf(stderr, "%s: Illegal color name.\n", NAME); + exit(1); + } + sprintf(backcolor, "%s", argv[i]); + } + continue; + } + + if (strcmp(argv[i], "-position") == 0) { + if (i < argc - 1) { + i++; + if (strlen(argv[i]) > 255) { + fprintf(stderr, "%s: Illegal position.\n", NAME); + exit(1); + } + sprintf(position, "%s", argv[i]); + } + continue; + } + + if (strcmp(argv[i], "-display") == 0) { + if (i < argc - 1) { + i++; + if (strlen(argv[i]) > 255) { + fprintf(stderr, "%s: Illegal display name.\n", NAME); + exit(1); + } + sprintf(display, "%s", argv[i]); + } + continue; + } } - if (strcmp(argv[i], "-w")==0) - wmaker=!wmaker; - if (strcmp(argv[i], "-s")==0) - ushape=!ushape; - if (strcmp(argv[i], "-a")==0) - astep=!astep; - if (strcmp(argv[i], "-novol")==0) - no_volume_display = 1; - if (strcmp(argv[i], "-d")==0 ) { - if (i= mixer_ctrl->devices_no ) { - fprintf(stderr, "%s : Sorry, this channel (%i) is " - "not supported.\n", NAME, current); - current = -1; - } - else{ - channel[channels]=current; - channels++; - } - } - if (strncmp(buf, "setchannel ", strlen("setchannel ")) == 0) { sscanf(buf, "setchannel %i", ¤t); - if (current >= mixer_ctrl->devices_no ) { - fprintf(stderr,"%s : Sorry, this channel (%i) is " + if (current >= mix->devices_no ) { + fprintf(stderr,"%s: Sorry, this channel (%i) is " "not supported.\n", NAME, current); current = -1; } } - if (strncmp(buf, "setname ", strlen("setname ")) == 0) { - if (current == -1) { - fprintf(stderr, "%s : Sorry, no current channel.\n", - NAME); - } else { - small_labels[current] = (char *) malloc(sizeof(char) * - 5); - sscanf(buf, "setname %4s", small_labels[current]); - } - } - if (strncmp(buf, "setmono ", strlen("setmono ")) == 0) { if (current == -1) { - fprintf(stderr,"%s : Sorry, no current channel.\n", + fprintf(stderr,"%s: Sorry, no current channel.\n", NAME); } else { int value; @@ -447,7 +698,7 @@ void readFile() { if (strncmp(buf, "setleft ", strlen("setleft ")) == 0 ) { if (current == -1) { - fprintf(stderr, "%s : Sorry, no current channel.\n", + fprintf(stderr, "%s: Sorry, no current channel.\n", NAME); } else { int value; @@ -459,7 +710,7 @@ void readFile() { if (strncmp(buf, "setright ", strlen("setright ")) == 0 ) { if (current == -1) { - fprintf(stderr, "%s : Sorry, no current channel.\n", + fprintf(stderr, "%s: Sorry, no current channel.\n", NAME); } else{ int value; @@ -475,9 +726,9 @@ void readFile() { } void checkVol(bool forced) { - Mixer_read_volume(channel[curchannel], true); - int nl = Mixer_read_left(channel[curchannel]); - int nr = Mixer_read_right(channel[curchannel]); + Mixer_read_volume(curchannel, true); + int nl = Mixer_read_left(curchannel); + int nr = Mixer_read_right(curchannel); if (forced ) { curleft=nl; curright=nr; @@ -487,81 +738,85 @@ void checkVol(bool forced) { else{ if (nl!=curleft || nr!=curright ) { if (nl!=curleft ) { - curleft=nl; - if (Mixer_get_stereo(channel[curchannel])) - drawLeft(); - else - drawMono(); + curleft=nl; + if (selems[curchannel]->stereo) + drawLeft(); + else + drawMono(); } if (nr!=curright ) { - curright=nr; - if (Mixer_get_stereo(channel[curchannel])) - drawRight(); - else - drawMono(); + curright=nr; + if (selems[curchannel]->stereo) + drawRight(); + else + drawMono(); } if (!no_volume_display) - drawVolLevel(); + drawVolLevel(); repaint(); } } } -void pressEvent(XButtonEvent *xev) -{ - if (xev->button == Button4 || xev->button == Button5) { - int inc; - if (xev->button == Button4) inc = 4; - else inc = -4; +void pressEvent(XButtonEvent *xev) { + int inc, x, y, v; - Mixer_read_volume(channel[curchannel], false); - Mixer_set_left(channel[curchannel], - CLAMP(Mixer_read_left(channel[curchannel]) + inc, 0, 100)); - Mixer_set_right(channel[curchannel], - CLAMP(Mixer_read_right(channel[curchannel]) + inc, 0, 100)); - Mixer_write_volume(channel[curchannel]); - checkVol(false); - return; - } + if (xev->button == Button4 || xev->button == Button5) { + if (xev->button == Button4) { + printf("inc\n"); + inc = 4; + } else { + printf("dec\n"); + inc = -4; + } - int x=xev->x-(winsize/2-32); - int y=xev->y-(winsize/2-32); - if (x>=5 && y>=47 && x<=17 && y<=57 ) { - curchannel--; - if (curchannel<0) - curchannel=channels-1; - btnstate |= BTNPREV; - rpttimer=0; - drawBtns(BTNPREV); - checkVol(true); - return; - } - if (x>=18 && y>=47 && x<=30 && y<=57 ) { - curchannel++; - if (curchannel>=channels) - curchannel=0; - btnstate|=BTNNEXT; - rpttimer=0; - drawBtns(BTNNEXT); - checkVol(true); - return; - } - if (x>=37 && x<=56 && y>=8 && y<=56 ) { - int v=((60-y)*100)/(2*25); - dragging=true; - if (x<=50) - Mixer_set_left(channel[curchannel], v); - if (x>=45) - Mixer_set_right(channel[curchannel], v); - Mixer_write_volume(channel[curchannel]); - checkVol(false); - return; - } - if (x>=5 && y>=21 && x<=30 && y<=42) { - drawText(small_labels[channel[curchannel]]); - return; - } + Mixer_read_volume(curchannel, false); + Mixer_set_left(curchannel, + CLAMP(Mixer_read_left(curchannel) + inc, 0, 100)); + Mixer_set_right(curchannel, + CLAMP(Mixer_read_right(curchannel) + inc, 0, 100)); + Mixer_write_volume(curchannel); + checkVol(false); + return; + } + x = xev->x - (winsize / 2 - 32); + y = xev->y - (winsize / 2 - 32); + if (x >= 5 && y >= 47 && x <= 17 && y <= 57) { + curchannel--; + if (curchannel < 0) + curchannel = mix->devices_no -1; + btnstate |= BTNPREV; + rpttimer = 0; + drawBtns(BTNPREV); + checkVol(true); + return; + } + if (x >= 18 && y >= 47 && x <= 30 && y <= 57) { + curchannel++; + if (curchannel >= mix->devices_no) + curchannel = 0; + btnstate|=BTNNEXT; + rpttimer = 0; + drawBtns(BTNNEXT); + checkVol(true); + return; + } + if (x >= 37 && x <= 56 && y >= 8 && y <= 56) { + v = ((60 - y) * 100) / (2 * 25); + dragging = true; + if (x <= 50) + Mixer_set_left(curchannel, v); + if (x >= 45) + Mixer_set_right(curchannel, v); + Mixer_write_volume(curchannel); + checkVol(false); + return; + } + if (x >= 5 && y >= 21 && x <= 30 && y <= 42) { + drawText(selems[curchannel]->name); + return; + } } void releaseEvent() { @@ -580,10 +835,10 @@ void motionEvent(XMotionEvent *xev) if (v<0) v=0; if (x<=50) - Mixer_set_left(channel[curchannel], v); + Mixer_set_left(curchannel, v); if (x>=45) - Mixer_set_right(channel[curchannel], v); - Mixer_write_volume(channel[curchannel]); + Mixer_set_right(curchannel, v); + Mixer_write_volume(curchannel); checkVol(false); } } @@ -595,50 +850,48 @@ void repaint() while(XCheckTypedEvent(d_display, Expose, &xev)); } -void update() -{ - drawText(small_labels[channel[curchannel]]); +void update() { + drawText(selems[curchannel]->name); - XCopyArea(d_display, pm_icon, pm_disp, gc_gc, icon[channel[curchannel]]*26, 0, 26, 24, 5, 19); - if (Mixer_get_stereo(channel[curchannel])) { - drawLeft(); - drawRight(); - } - else { - drawMono(); - } + XCopyArea(d_display, pm_icon, pm_disp, gc_gc, + selems[curchannel]->iconIndex * 26, 0, 26, 24, 5, 19); + if (selems[curchannel]->stereo) { + drawLeft(); + drawRight(); + } else { + drawMono(); + } } -void drawText(char *text) -{ - char *p = text; - char p2; - int i; +void drawText(char *text) { + char *p = text; + char p2; + int i; - for (i=0; i<4; i++, p++) { - p2 = toupper(*p); - if (p2 >= 'A' && p2 <= 'Z') { - XCopyArea(d_display, pm_chars, pm_disp, gc_gc, 6*((int)p2-65), 0, 6, 9, 5+(i*6), 5); + for (i = 0; i < 4; i++, p++) { + p2 = toupper(*p); + if (p2 >= 'A' && p2 <= 'Z') { + XCopyArea(d_display, pm_chars, pm_disp, gc_gc, + 6 * ((int)p2 - 65), 0, 6, 9, 5 + (i * 6), 5); + } else if (p2 >= '0' && p2 <= '9') { + XCopyArea(d_display, pm_digits, pm_disp, gc_gc, + 6 * ((int)p2 - 48), 0, 6, 9, 5 + (i * 6), 5); + } else { + if (p2 == '\0') + p--; + XCopyArea(d_display, pm_digits, pm_disp, gc_gc, 60, 0, 6, 9, + 5 + (i * 6), 5); + } } - else if (p2 >= '0' && p2 <= '9') { - XCopyArea(d_display, pm_digits, pm_disp, gc_gc, 6*((int)p2-48), 0, 6, 9, 5+(i*6), 5); - } - else { - if (p2 == '\0') - p--; - XCopyArea(d_display, pm_digits, pm_disp, gc_gc, 60, 0, 6, 9, 5+(i*6), 5); - } - } - if (!no_volume_display) - text_counter = 10; + if (!no_volume_display) + text_counter = 10; } void drawVolLevel() { int i; int digits[4]; - int vol = (Mixer_read_left(channel[curchannel]) + - Mixer_read_right(channel[curchannel])) / 2; + int vol = (Mixer_read_left(curchannel) + Mixer_read_right(curchannel)) / 2; digits[0] = (vol/100) ? 1 : 10; digits[1] = (vol/10) == 10 ? 0 : (vol/10); @@ -730,7 +983,7 @@ See the README file for a more complete notice.\n\n", stdout); -a use smaller window (for AfterStep Wharf)\n\ -l led_color use the specified color for led display\n\ -b back_color use the specified color for backgrounds\n\ - -d mix_device use specified device (rather than /dev/mixer)\n\ + -d alsa_device use specified device (rather than 'default')\n\ -position position set window position (see X manual pages)\n\ -display display select target display (see X manual pages)\n\n", stdout); diff --git a/wmamixer.h b/wmamixer.h index 95137bb..6e55e2b 100644 --- a/wmamixer.h +++ b/wmamixer.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -46,6 +47,10 @@ #undef CLAMP #define CLAMP(v, l, h) (((v) > (h)) ? (h) : (((v) < (l)) ? (l) : (v))) +/* Function to convert from percentage to volume. val = percentage */ +#define convert_prange1(val, min, max) \ + ceil((val) * ((max) - (min)) * 0.01 + (min)) + // Pixmaps - standard Pixmap pm_main; @@ -77,7 +82,7 @@ int winsize; bool no_volume_display = 0; // Variables for command-line arguments - custom -char mixer_device[256] = "default"; +char card[256] = "default"; char backcolor[256] = BACKCOLOR; char ledcolor[256] = LEDCOLOR; @@ -96,7 +101,7 @@ unsigned long color[4]; int text_counter = 0; -// Misc custom global variables +// Misc custom global variables // ---------------------------- // Current state information @@ -116,27 +121,49 @@ int rpttimer = 0; // For draggable volume control bool dragging = false; -int channels = 2; -int channel[25]; -int icon[25] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24}; -char *small_labels[25] = {"vol ", "bass", "trbl", "synt", "pcm ", - "spkr", "line", "mic ", "cd ", "mix ", "pcm2", "rec ", "igai", "ogai", - "lin1", "lin2", "lin3", "dig1", "dig2", "dig3", "phin", "phou", "vid ", - "rad ", "mon "}; +int channel[32]; +int icon[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; + +struct Selem { + char *name; + bool stereo; + int currentVolRight; + int currentVolLeft; + short int iconIndex; + snd_mixer_elem_t *elem; + long min; + long max; + bool capture; + snd_mixer_selem_channel_id_t channels[2]; + +}; + +typedef struct { + bool isvolume; + bool capture; + bool mono; +} slideCaptureMono; + +struct NamesCount { + short int pcm, line, lineb, mic, micb, capt, vol; +} namesCount = {1, 1, 1, 1, 1, 1, 1}; + +struct Selem *selems[32]; struct Mixer { - int openOK; int devices_no; + snd_mixer_t * handle; + void *elems[32]; }; +static int smixer_level = 0; +static struct snd_mixer_selem_regopt smixer_options; + // Procedures and functions - standard void initXWin(int argc, char **argv); void freeXWin(); void createWin(Window *win, int x, int y); -unsigned long getColor(char *colorname); -unsigned long mixColor(char *colorname1, int prop1, char *colorname2, - int prop2); +unsigned long mixColor(char *color1, int prop1, char *color2, int prop2); // Procedures and functions - custom void scanArgs(int argc, char **argv); @@ -156,14 +183,18 @@ void drawText(char *text); void drawBtns(int btns); void drawBtn(int x, int y, int w, int h, bool down); -struct Mixer *Mixer_create(char *device); +void Mixer_set_selem_props(struct Selem *selem, const char *name); +slideCaptureMono Mixer_getcapabilities(snd_mixer_elem_t *elem); + +struct Mixer *Mixer_create(char *devicename); void Mixer_set_left(int current, int value); void Mixer_set_right(int current, int value); void Mixer_write_volume(int current); int Mixer_read_left(int current); int Mixer_read_right(int current); -int Mixer_read_volume(int channel, bool read); -bool Mixer_get_stereo(int channel); +int Mixer_read_volume(int current, bool read); + +void Mixer_set_limits(snd_mixer_elem_t *elem, struct Selem *selem); void Mixer_destroy(struct Mixer *mix);