/* command-line Audio Control Panel for sparcs running SunOS or Solaris by Roger Espel Llima (orabidoo) Started: 16 Mar 1996 Compile with: [g]cc acl.c -o acl -lm # for SunOS 4.x [g]cc acl.c -DSOLARIS -o acl -lm # for Solaris */ #include #include #include #include #include #include #include /* try to catch a missing -DSOLARIS */ #ifndef SOLARIS #ifdef __SVR4 #define SOLARIS #endif #endif #ifdef SOLARIS #include #else #include #include #endif char *myname; int afd, afd2, realdev = 0, force = 0, volume_only = 0; struct audio_info ainfo, ainfo0, ainfo1, forceainfo; void bug(char *s) { fprintf(stderr, "%s: %s; try %s -help\n", myname, s, myname); exit(1); } void help() { printf("Use: %s [options] [volume]\n", myname); printf("Options: -v[olume] number -- sets the volume\n"); printf(" -m[onitor] number -- sets the monitor gain\n"); printf(" -r[ecord] number -- sets the record gain\n"); printf(" -s[pkr], -speaker -- output to speaker\n"); printf(" -j[ack], -headphones -- output to headphones\n"); printf(" -lo, -lineout -- output to lineout\n"); printf(" -mi, -mike -- input from microphone\n"); printf(" -l[ine], -linein -- input from linein\n"); printf(" -pause, -stop -- pause playback\n"); printf(" -cont, -resume -- resume playback\n"); printf(" -rpause, -rstop -- pause recording\n"); printf(" -rcont, -rresume -- resume recording\n"); printf(" -b[al], -balance -- output balance (0-100)\n"); printf(" -rb[al], -rbalance -- input balance (0-100)\n"); printf(" -8bit -- 8-bit audio\n"); printf(" -16bit -- 16-bit audio\n"); printf(" -st, -stereo -- stereo\n"); printf(" -mo, -mono -- mono\n"); printf(" -u-law, -ulaw -- u-law encoding\n"); printf(" -a-law, -alaw -- A-law encoding\n"); printf(" -linear, -pcm -- linear PCM encoding\n"); printf(" -rate num, -hz num -- sampling rate in Hz\n"); printf(" -hifi -- 16-bit stereo linear 48000 Hz\n"); printf(" -force -- re-set values when changed\n"); printf("Volumes are from 0 to 100.\n"); printf("Balances are from 0 (left) to 100 (right).\n"); exit(0); } int togain(int n) { return (AUDIO_MIN_GAIN + (int)rint(((double)(AUDIO_MAX_GAIN - AUDIO_MIN_GAIN)) * ((double)n / (double)100))); } int to100(int n) { return ((int)rint((double)100 * (((double)(n - AUDIO_MIN_GAIN)) / (double)(AUDIO_MAX_GAIN - AUDIO_MIN_GAIN)))); } int tobal(int n) { return (AUDIO_LEFT_BALANCE + (int)rint(((double)(AUDIO_RIGHT_BALANCE - AUDIO_LEFT_BALANCE)) * ((double)n / (double)100))); } int balto100(int n) { return ((int)rint((double)100 * (((double)(n - AUDIO_LEFT_BALANCE)) / (double)(AUDIO_RIGHT_BALANCE - AUDIO_LEFT_BALANCE)))); } int samplerate(int n) { static int srs[] = { 8000, 9600, 11025, 16000, 18900, 22050, 32000, 37800, 44100, 48000, 0 }; int r = 0, *p; for (p = srs; *p; p++) if (abs(*p - n) < abs(r - n)) r = *p; if (r == 0) { fprintf(stderr, "Invalid sample rate; valid values are:\n8000, 9600, 11025, 16000, 18900, 22050, 32000, 37800, 44100, 48000\n"); exit(1); } if (r != n) fprintf(stderr, "Adjusting sample rate to %d\n", r); return r; } char *stereo(int n) { static char *s_stereo = "stereo", *s_mono = "mono"; if (n == 1) return s_mono; else return s_stereo; } char *encoding (int n) { static char *s_ulaw = "u-law", *s_alaw = "A-law", *s_linear = "linear"; static char *s_unrec = "unrecognized encoding"; if (n == AUDIO_ENCODING_ULAW) return s_ulaw; else if (n == AUDIO_ENCODING_ALAW) return s_alaw; else if (n == AUDIO_ENCODING_LINEAR) return s_linear; else return s_unrec; } int exactsamectl(struct audio_info *a1, struct audio_info *a2) { return (a1->play.gain == a2->play.gain && a1->record.gain == a2->record.gain && a1->monitor_gain == a2->monitor_gain && a1->play.port == a2->play.port && a1->record.port == a2->record.port && a1->play.balance == a2->play.balance && a1->record.balance == a2->record.balance); } int samectl(struct audio_info *a1, struct audio_info *a2) { /* a1->field can be anything if a2->field is unset */ return ((a1->play.gain == a2->play.gain || a2->play.gain == ainfo0.play.gain) && (a1->record.gain == a2->record.gain || a2->record.gain == ainfo0.record.gain) && (a1->monitor_gain == a2->monitor_gain || a2->monitor_gain == ainfo0.monitor_gain) && (a1->play.port == a2->play.port || a2->play.port == ainfo0.play.port) && (a1->record.port == a2->record.port || a2->record.port == ainfo0.record.port) && (a1->play.balance == a2->play.balance || a2->play.balance == ainfo0.play.balance) && (a1->record.balance == a2->record.balance || a2->record.balance == ainfo0.record.balance)); } int isnumber(char *s) { while (*s) { if (!(*s >= '0' && *s <= '9')) return 0; s++; } return 1; } void modified() { int r; r = ioctl(afd, AUDIO_GETINFO, &ainfo1); if (r != 0) { perror("can't get audioctl info"); exit(1); } ainfo = forceainfo; if (!samectl(&ainfo1, &ainfo)) { r = ioctl(afd, AUDIO_SETINFO, &ainfo); if (r != 0) { perror("can't set audioctl info"); exit(1); } } #ifdef SOLARIS signal(SIGPOLL, modified); #endif } int main(int argc, char *argv[]) { int r, idx; char *s; myname = argv[0]; if (strlen(myname) >= 6 && strcmp(myname + strlen(myname) - 6, "volume") == 0) volume_only = 1; if (argc <= 1) { /* asking for status only */ afd = open("/dev/audioctl", O_RDWR); if (afd<0) { perror("can't open audioctl device"); exit(1); } r = ioctl(afd, AUDIO_GETINFO, &ainfo); if (r != 0) { perror("can't get audioctl info"); exit(1); } if (volume_only) { printf("%d\n", to100(ainfo.play.gain)); exit(to100(ainfo.play.gain)); } printf("Volume : %d\n", to100(ainfo.play.gain)); printf("Monitor Gain : %d\n", to100(ainfo.monitor_gain)); printf("Record Gain : %d\n", to100(ainfo.record.gain)); if (ainfo.play.port == AUDIO_SPEAKER) printf("Output to : speaker\n"); else if (ainfo.play.port == AUDIO_HEADPHONE) printf("Output to : headphones\n"); else if (ainfo.play.port == AUDIO_LINE_OUT) printf("Output to : line out\n"); if (ainfo.record.port == AUDIO_MICROPHONE) printf("Input from : mike\n"); else if (ainfo.record.port == AUDIO_LINE_IN) printf("Input from : line in\n"); printf("Balance : %d\n", balto100(ainfo.play.balance)); printf("Rec. balance : %d\n", balto100(ainfo.record.balance)); printf("Input channel : %d-bit %s %s %d Hz\n", ainfo.record.precision, stereo(ainfo.record.channels), encoding(ainfo.record.encoding), ainfo.record.sample_rate); printf("Output channel : %d-bit %s %s %d Hz\n", ainfo.play.precision, stereo(ainfo.play.channels), encoding(ainfo.play.encoding), ainfo.play.sample_rate); if (ainfo.play.pause) printf("Playback is paused\n"); if (ainfo.record.pause) printf("Recording is paused\n"); exit(0); } idx = 1; afd = open("/dev/audioctl", O_RDWR); if (afd<0) { perror("can't open audioctl device"); exit(1); } AUDIO_INITINFO(&ainfo); AUDIO_INITINFO(&ainfo0); r = ioctl(afd, AUDIO_GETINFO, &ainfo1); if (r != 0) { perror("can't get audioctl info"); exit(1); } while (idx < argc) { s = argv[idx++]; while (*s == '-') s++; if (*s == 0) continue; if (isnumber(s)) { ainfo.play.gain = togain(atoi(s)); } else if (strcmp(s, "v")==0 || strcmp(s, "volume")==0) { if (idx >= argc) bug("volume: missing argument"); s = argv[idx++]; ainfo.play.gain = togain(atoi(s)); } else if (strcmp(s, "m")==0 || strcmp(s, "monitor")==0) { if (idx >= argc) bug("monitor: missing argument"); s = argv[idx++]; ainfo.monitor_gain = togain(atoi(s)); } else if (strcmp(s, "r")==0 || strcmp(s, "record")==0) { if (idx >= argc) bug("record: missing argument"); s = argv[idx++]; ainfo.record.gain = togain(atoi(s)); } else if (strcmp(s, "s")==0 || strcmp(s, "spkr")==0 || strcmp(s, "speaker")==0) { ainfo.play.port = AUDIO_SPEAKER; } else if (strcmp(s, "j")==0 || strcmp(s, "headphones")==0 || strcmp(s, "jack")==0) { ainfo.play.port = AUDIO_HEADPHONE; } else if (strcmp(s, "lo")==0 || strcmp(s, "lineout")==0) { ainfo.play.port = AUDIO_LINE_OUT; } else if (strcmp(s, "mi")==0 || strcmp(s, "mike")==0) { ainfo.record.port = AUDIO_MICROPHONE; } else if (strcmp(s, "l")==0 || strcmp(s, "li")==0 || strcmp(s, "linein")==0) { ainfo.record.port = AUDIO_LINE_IN; } else if (strcmp(s, "pause")==0 || strcmp(s, "stop")==0) { ainfo.play.pause = 1; } else if (strcmp(s, "cont")==0 || strcmp(s, "resume")==0) { ainfo.play.pause = 0; } else if (strcmp(s, "rpause")==0 || strcmp(s, "rstop")==0) { ainfo.record.pause = 1; } else if (strcmp(s, "rcont")==0 || strcmp(s, "rresume")==0) { ainfo.record.pause = 0; } else if (strcmp(s, "b")==0 || strcmp(s, "balance")==0 || strcmp(s, "bal")==0) { if (idx >= argc) bug("balance: missing argument"); s = argv[idx++]; ainfo.play.balance=tobal(atoi(s)); } else if (strcmp(s, "rb")==0 || strcmp(s, "rbalance")==0 || strcmp(s, "rbal")==0) { if (idx >= argc) bug("rbalance: missing argument"); s = argv[idx++]; ainfo.record.balance=tobal(atoi(s)); } else if (strcmp(s, "stereo")==0 || strcmp(s, "st")==0) { realdev = 1; ainfo1.play.channels = ainfo1.record.channels = 2; /* stereo => 16bit linear */ ainfo1.play.encoding = ainfo1.record.encoding = AUDIO_ENCODING_LINEAR; ainfo1.play.precision = ainfo1.record.precision = 16; } else if (strcmp(s, "mono")==0 || strcmp(s, "mo")==0) { realdev = 1; ainfo1.play.channels = ainfo1.record.channels = 1; } else if (strcmp(s, "8bit")==0) { realdev = 1; ainfo1.play.precision = ainfo1.record.precision = 8; /* 8bit => 8kHz mono u/a-law */ ainfo1.play.sample_rate = ainfo1.record.sample_rate = 8000; ainfo1.play.channels = ainfo1.record.channels = 1; if (ainfo1.play.encoding == AUDIO_ENCODING_LINEAR || ainfo1.record.encoding == AUDIO_ENCODING_LINEAR) ainfo1.play.encoding = ainfo1.record.encoding = AUDIO_ENCODING_ULAW; } else if (strcmp(s, "16bit")==0) { realdev = 1; ainfo1.play.precision = ainfo1.record.precision = 16; /* 16bit => linear */ ainfo1.play.encoding = ainfo1.record.encoding = AUDIO_ENCODING_LINEAR; } else if (strcmp(s, "rate")==0 || strcmp(s, "hz")==0 || strcmp(s, "Hz")==0) { if (idx >= argc) bug("rate: missing argument"); realdev = 1; s = argv[idx++]; ainfo1.play.sample_rate = ainfo1.record.sample_rate = samplerate(atoi(s)); /* rate != 8000 => 16bit linear */ if (ainfo1.play.sample_rate != 8000) { ainfo1.play.encoding = ainfo1.record.encoding = AUDIO_ENCODING_LINEAR; ainfo1.play.precision = ainfo1.record.precision = 16; } } else if (strcasecmp(s, "ulaw")==0 || strcasecmp(s, "u-law")==0 || strcasecmp(s, "u_law")==0) { realdev = 1; ainfo1.play.encoding = ainfo1.record.encoding = AUDIO_ENCODING_ULAW; /* ulaw => 8bit mono 8kHz */ ainfo1.play.precision = ainfo1.record.precision = 8; ainfo1.play.channels = ainfo1.record.channels = 1; ainfo1.play.sample_rate = ainfo1.record.sample_rate = 8000; } else if (strcasecmp(s, "alaw")==0 || strcasecmp(s, "a-law")==0 || strcasecmp(s, "a_law")==0) { realdev = 1; ainfo1.play.encoding = ainfo1.record.encoding = AUDIO_ENCODING_ALAW; /* alaw => 8bit mono 8kHz */ ainfo1.play.precision = ainfo1.record.precision = 8; ainfo1.play.channels = ainfo1.record.channels = 1; ainfo1.play.sample_rate = ainfo1.record.sample_rate = 8000; } else if (strcmp(s, "linear")==0 || strcasecmp(s, "PCM")==0) { realdev = 1; ainfo1.play.encoding = ainfo1.record.encoding = AUDIO_ENCODING_LINEAR; /* linear => 16bit */ ainfo1.play.precision = ainfo1.record.precision = 16; } else if (strcmp(s, "hifi")==0) { realdev = 1; ainfo1.play.encoding = ainfo1.record.encoding = AUDIO_ENCODING_LINEAR; ainfo1.play.precision = ainfo1.record.precision = 16; ainfo1.play.channels = ainfo1.record.channels = 2; ainfo1.play.sample_rate = ainfo1.record.sample_rate = 48000; } else if (strcmp(s, "force")==0) { force = 1; } else { if (strcmp(s, "help")==0 || strcmp(s, "?")==0 || strcmp(s, "h")==0) help(); else { static char msg[200]; sprintf(msg, "unrecognized option: ``%s''", s); bug(msg); } } } forceainfo = ainfo; if (realdev) { afd2 = open("/dev/audio", O_RDWR | O_NDELAY); if (afd2<0) { perror("can't open audio device in nonblocking mode"); exit(1); } r = ioctl(afd2, AUDIO_SETINFO, &ainfo1); if (r != 0) { perror("can't set audioctl info"); exit(1); } close(afd2); } if (!exactsamectl(&ainfo, &ainfo0)) { r = ioctl(afd, AUDIO_SETINFO, &ainfo); if (r != 0) { perror("can't set audioctl info"); exit(1); } } if (force) { if (exactsamectl(&forceainfo, &ainfo0)) { fprintf(stderr, "%s: nothing to force\n", myname); exit(1); } r = ioctl(afd, AUDIO_GETINFO, &ainfo); if (r != 0) { perror("can't get audioctl info"); exit(1); } if (forceainfo.play.gain != ainfo0.play.gain) forceainfo.play.gain = ainfo.play.gain; if (forceainfo.record.gain != ainfo0.record.gain) forceainfo.record.gain = ainfo.record.gain; if (forceainfo.monitor_gain != ainfo0.monitor_gain) forceainfo.monitor_gain = ainfo.monitor_gain; if (forceainfo.play.port != ainfo0.play.port) forceainfo.play.port = ainfo.play.port; if (forceainfo.record.port != ainfo0.record.port) forceainfo.record.port = ainfo.record.port; if (forceainfo.play.balance != ainfo0.play.balance) forceainfo.play.balance = ainfo.play.balance; if (forceainfo.record.balance != ainfo0.record.balance) forceainfo.record.balance = ainfo.record.balance; signal(SIGPOLL, modified); r = ioctl(afd, I_SETSIG, S_MSG); if (r != 0) { perror("can't initialize polling"); exit(1); } while (1) sleep(1000000); } return 0; }