mixer.c

Go to the documentation of this file.
00001 /*   
00002  *  mixer
00003  *
00004  *  Michel R. Prevenier.
00005  */
00006 
00007 #include <sys/types.h>
00008 #include <errno.h>
00009 #include <curses.h>
00010 #include <signal.h>
00011 #include <stdlib.h>
00012 #include <unistd.h>
00013 #include <fcntl.h>
00014 #include <stdio.h>
00015 #include <string.h>
00016 #include <sys/ioctl.h>
00017 #include <minix/sound.h>
00018 
00019 #define CURS_CTRL       '\033'
00020 #define ESCAPE          27
00021 #define UP              'A'
00022 #define DOWN            'B'
00023 #define LEFT            'D'
00024 #define RIGHT           'C'
00025 #define SPACE           ' '
00026 
00027 
00028 _PROTOTYPE ( int main, (int arg, char **argv));
00029 _PROTOTYPE ( void usage, (void));
00030 _PROTOTYPE ( void non_interactive, (void));
00031 _PROTOTYPE ( void setup_screen, (void));
00032 _PROTOTYPE ( int read_settings, (void));
00033 _PROTOTYPE ( int write_settings, (void));
00034 _PROTOTYPE ( void rdwr_levels, (int flag));
00035 _PROTOTYPE ( void rdwr_inputs, (int flag));
00036 _PROTOTYPE ( void rdwr_outputs, (int flag));
00037 _PROTOTYPE ( void create_slider, (int x, int y, enum Device device));
00038 _PROTOTYPE ( void show_inputs, (int x, int y));
00039 _PROTOTYPE ( void show_outputs, (int x, int y));
00040 _PROTOTYPE ( char *d_name, (enum Device device, char *name));
00041 _PROTOTYPE ( void user_interface, (void));
00042 _PROTOTYPE ( void terminate, (int s));
00043 
00044 WINDOW *main_win;
00045 int old_stdin;
00046 int fd;
00047 char name[9];
00048 char *file_name;
00049 struct volume_level levels[9];
00050 struct inout_ctrl inputs_left[9];
00051 struct inout_ctrl inputs_right[9];
00052 struct inout_ctrl outputs[9];
00053 
00054 
00055 void usage()
00056 {
00057   fprintf(stderr, "Usage: mixer [-r]\n");
00058   exit(-1);
00059 }
00060 
00061 
00062 void terminate(s)
00063 int s;
00064 {
00065   /* Restore terminal parameters and exit */
00066 
00067   (void) fcntl(0,F_SETFL,old_stdin);
00068   move(23, 0);                  
00069   refresh();                    
00070   resetty();
00071   endwin();                     
00072   exit(1);              
00073 }
00074 
00075 
00076 int write_settings()
00077 {
00078   /* Write the current mixer settings to $HOME/.mixer */
00079 
00080   int fd;
00081 
00082   if ((fd = creat(file_name, 0x124)) > 0)
00083   {
00084     write(fd, levels, sizeof(levels));
00085     write(fd, inputs_left, sizeof(inputs_left));
00086     write(fd, inputs_right, sizeof(inputs_right));
00087     write(fd, outputs, sizeof(outputs));
00088     close(fd);
00089     return 1;
00090   }
00091 
00092   return 0;
00093 }
00094 
00095 
00096 int read_settings()
00097 {
00098   /* Restore mixer settings saved in $HOME/.mixer */
00099 
00100   int fd;
00101 
00102   if ((fd = open(file_name, O_RDONLY)) > 0)
00103   {
00104     read(fd, levels, sizeof(levels));
00105     read(fd, inputs_left, sizeof(inputs_left));
00106     read(fd, inputs_right, sizeof(inputs_right));
00107     read(fd, outputs, sizeof(outputs));
00108     close(fd);
00109     rdwr_levels(1);
00110     rdwr_outputs(1);
00111     rdwr_inputs(1);
00112     return 1;
00113   }
00114   return 0;
00115 }
00116 
00117 
00118 void rdwr_levels(flag)
00119 int flag;             /* 0 = read, 1 = write */
00120 {
00121   /* Get or set mixer settings */
00122 
00123   int i;
00124   int cmd;
00125  
00126   cmd = (flag == 0 ? MIXIOGETVOLUME : MIXIOSETVOLUME);  
00127   
00128   for(i = Master; i <= Bass; i++)
00129     (void) (ioctl(fd, cmd, &levels[i])); 
00130 }    
00131 
00132 
00133 void rdwr_inputs(flag)
00134 int flag;              /* 0 = read, 1 = write */
00135 {
00136   /* Get or set input settings */
00137 
00138   int i;
00139   int cmd_left, cmd_right;
00140   
00141   cmd_left = (flag == 0 ? MIXIOGETINPUTLEFT : MIXIOSETINPUTLEFT);  
00142   cmd_right = (flag == 0 ? MIXIOGETINPUTRIGHT : MIXIOSETINPUTRIGHT);  
00143 
00144   for(i = Fm; i <= Mic; i++)
00145   {
00146     (void) (ioctl(fd, cmd_left, &inputs_left[i])); 
00147     (void) (ioctl(fd, cmd_right, &inputs_right[i])); 
00148   }
00149 }
00150 
00151 
00152 void rdwr_outputs(flag)
00153 int flag;               /* 0 = read, 1 = write */
00154 {
00155   /* Get or set output settings */
00156 
00157   int i;
00158   int cmd; 
00159 
00160   cmd = (flag == 0 ? MIXIOGETOUTPUT : MIXIOSETOUTPUT);  
00161 
00162   for(i = Cd; i <= Mic; i++)
00163     (void) (ioctl(fd, cmd, &outputs[i])); 
00164 }
00165 
00166 
00167 int main(argc, argv)
00168 int argc;
00169 char **argv;
00170 
00171 {
00172   int i;
00173   char *home_ptr;
00174   int fd2;
00175 
00176   /* Open mixer */
00177   if ((fd = open("/dev/mixer",O_RDONLY)) < 0)
00178   {
00179     fprintf(stderr, "Cannot open /dev/mixer\n");
00180     exit(-1);
00181   }
00182 
00183   /* Get user's home directory and construct the $HOME/.mixer
00184    * file name 
00185    */
00186   home_ptr = getenv("HOME");
00187   file_name = malloc(strlen(home_ptr)+strlen("mixer.ini\0"));
00188   if (file_name == (char *)0) 
00189   {
00190     fprintf(stderr, "Not enough memory\n");
00191     exit(-1);
00192   }
00193   strncpy(file_name, home_ptr, strlen(home_ptr));
00194   strncpy(file_name+strlen(home_ptr), "/.mixer\0", 9);
00195 
00196   /* Fill in the device numbers */    
00197   for(i = Master; i <= Bass; i++) 
00198   {
00199     levels[i].device = i;
00200     inputs_left[i].device = i;
00201     inputs_right[i].device = i;
00202     outputs[i].device = i;
00203   }
00204 
00205   /* Get arguments */
00206   if (argc > 1)
00207   {
00208     if (strncmp(argv[1], "-r", 2) == 0)
00209     {
00210       if (read_settings())
00211       {
00212         printf("Mixer settings restored\n");
00213         exit(0);
00214       }
00215       else
00216       {
00217         fprintf(stderr, "Could not restore mixer settings\n");
00218         exit(-1);
00219       }
00220     } 
00221     else usage();
00222   }
00223 
00224   /* Initialize windows. */
00225   (void) initscr();
00226   signal(SIGINT, terminate);
00227   old_stdin = fcntl(0,F_GETFL);
00228   cbreak();
00229   noecho();
00230   main_win = newwin(23,80,0,0);
00231   scrollok(main_win, FALSE);
00232 
00233   /* Read all current mixer settings */
00234   rdwr_levels(0);
00235   rdwr_inputs(0);
00236   rdwr_outputs(0);
00237 
00238   /* Set up the user screen and handle user input */
00239   setup_screen();
00240   user_interface();
00241 }
00242 
00243 
00244 void user_interface()
00245 {
00246   /* This is the user interface. */
00247  
00248   char c;
00249   int x,y;
00250   int right;
00251   int input_scr, input_pos;
00252   int output_scr, output_pos;
00253   int max_level;
00254   enum Device device;
00255   int fd2;
00256  
00257   device = Master;
00258   right = 0;
00259   input_scr = 0;
00260   output_scr = 0;
00261   input_pos = 0;
00262   output_pos = 0;
00263 
00264   while(1)
00265   {
00266     if (input_scr)
00267     {
00268       y = device + 9;
00269       x = 51 + input_pos + (device == Mic ? 2 : 0);
00270     }
00271     else if (output_scr)
00272     {
00273       y = device + 15;
00274       x = 53 + output_pos + (device == Mic ? 4 : 0);
00275     }
00276     else
00277     {
00278       y = (device != Speaker ? 2 : 1) + 
00279           (device - (device < Treble ? 0 : Treble)) * 3 + 
00280           (right == 0 ? 0 : 1);
00281       if (!right)
00282         x = 9 + levels[device].left / (device < Speaker ? 2 : 1 ) +
00283               (device > Speaker ? 39 : 0);
00284       else
00285         x = 9 + levels[device].right / (device < Speaker ? 2 : 1) +
00286               (device > Speaker ? 39 : 0);
00287     }
00288     
00289     wmove(main_win,y,x);
00290     wrefresh(main_win);
00291     c = wgetch(main_win);
00292 
00293     switch(c)
00294     {
00295       case CURS_CTRL:
00296       {
00297         (void) wgetch(main_win);
00298         c = wgetch(main_win);
00299         
00300         switch(c)
00301         { 
00302           case DOWN: 
00303           {
00304            if (output_scr) 
00305            {
00306              if (device < Mic)
00307              {
00308                 device++;
00309                 if (device == Mic) output_pos = 0;
00310              }
00311            }
00312            else if (right || input_scr)
00313            {
00314              if (!input_scr)
00315              {
00316                if (device < Bass) 
00317                {
00318                  device++;         
00319                  right = 0;
00320                }
00321                else
00322                {  
00323                  input_scr = 1;
00324                  input_pos = 0;
00325                  device = Fm;
00326                }
00327              }
00328              else
00329              {
00330                if (device < Mic) 
00331                {
00332                  device++;
00333                  if (device == Mic && input_pos > 8) input_pos = 8;
00334                }
00335                else 
00336                { 
00337                  device = Cd; 
00338                  output_scr = 1; 
00339                  input_scr = 0; 
00340                  output_pos = 0; 
00341                }
00342              }
00343            }
00344            else 
00345            {
00346              if (device != Mic && device != Speaker)  right = 1;
00347              else { device++; right = 0; }
00348            }
00349           };break;
00350           case UP: 
00351           {
00352            if (output_scr) 
00353            {
00354              if (device > Cd) device--;
00355              else 
00356              {
00357                device = Mic; 
00358                output_scr = 0;
00359                input_scr = 1;
00360              }
00361            }
00362            else if (!right || input_scr)
00363            {
00364              if (input_scr)
00365              {
00366                if (device > Fm) device--;
00367                else 
00368                {
00369                  input_scr = 0;
00370                  device = Bass;
00371                  right = 1;
00372                }
00373              }
00374              else 
00375              {
00376                if (device > Master) 
00377                {
00378                  device--;         
00379                  if (device != Mic && device != Speaker) right = 1;
00380                }
00381              }
00382            }
00383            else 
00384              right = 0;
00385           };break;
00386           case RIGHT: 
00387           {
00388             if (output_scr) 
00389             {
00390               if (output_pos < 8 && device != Mic) output_pos = 8;
00391             }
00392             else if (!input_scr)
00393             {
00394               if (device < Speaker) max_level = 31;
00395               else if (device > Speaker) max_level = 15;
00396               else max_level = 4;
00397 
00398               if (!right) 
00399               {
00400                 if (levels[device].left < max_level) levels[device].left+=
00401                   (device < Speaker ? 2 : 1);
00402               }
00403               else
00404               {
00405                 if (levels[device].right < max_level) levels[device].right+=
00406                   (device < Speaker ? 2 : 1);
00407               }
00408               ioctl(fd, MIXIOSETVOLUME, &levels[device]); 
00409               ioctl(fd, MIXIOGETVOLUME, &levels[device]); 
00410               create_slider(1 + (device < Treble ? 0 : 39), 
00411                             (device - (device < Treble ? 0 : Treble))*3 +
00412                             (device != Speaker ? 2 : 1), device);
00413             }
00414             else
00415             {
00416               if ((device != Mic && input_pos < 12) ||
00417                   (device == Mic && input_pos < 8))
00418                 input_pos += (4 + (device == Mic ? 4 : 0));
00419             }
00420           };break;
00421           case LEFT: 
00422           {
00423             if (output_scr)
00424             {
00425               if (output_pos > 0) output_pos = 0;
00426             }
00427             else if (!input_scr)
00428             {
00429               if (!right)
00430               {
00431                 if (levels[device].left > 0) levels[device].left-=
00432                   (device < Speaker ? 2 : 1);
00433               }
00434               else
00435               {
00436                 if (levels[device].right > 0) levels[device].right-=
00437                   (device < Speaker ? 2 : 1);
00438               }
00439               ioctl(fd, MIXIOSETVOLUME, &levels[device]); 
00440               ioctl(fd, MIXIOGETVOLUME, &levels[device]); 
00441               create_slider(1 + (device < Treble ? 0 : 39), 
00442                             (device - (device < Treble ? 0 : Treble))*3 +
00443                             (device != Speaker ? 2 : 1), device);
00444             }
00445             else
00446             {
00447               if (input_pos > 0) 
00448                 input_pos -= (4 + (device == Mic ? 4 : 0));
00449             } 
00450           };break;
00451         } 
00452       };break;
00453     case SPACE:
00454       {
00455         if (output_scr)
00456         {
00457           switch(output_pos)
00458           {
00459             case 0:
00460             case 4:
00461             {
00462               outputs[device].left = 
00463                (outputs[device].left == ON ? OFF : ON);
00464               ioctl(fd, MIXIOSETOUTPUT, &outputs[device]);
00465             };break;
00466             case 8:
00467             {
00468               outputs[device].right = 
00469                (outputs[device].right == ON ? OFF : ON);
00470               ioctl(fd, MIXIOSETOUTPUT, &outputs[device]);
00471             };break;
00472           }
00473           ioctl(fd, MIXIOGETOUTPUT, &outputs[device]);
00474           show_outputs(41,16);
00475         }
00476         else if (input_scr)
00477         { 
00478           switch(input_pos)
00479           {
00480             case 0:
00481             {
00482               inputs_left[device].left = 
00483                (inputs_left[device].left == ON ? OFF : ON);
00484               ioctl(fd, MIXIOSETINPUTLEFT, &inputs_left[device]);
00485             };break;
00486             case 4:
00487             {
00488               inputs_left[device].right = 
00489                (inputs_left[device].right == ON ? OFF : ON);
00490               ioctl(fd, MIXIOSETINPUTLEFT, &inputs_left[device]);
00491             };break;
00492             case 8:
00493             {
00494               inputs_right[device].left = 
00495                (inputs_right[device].left == ON ? OFF : ON);
00496               ioctl(fd, MIXIOSETINPUTRIGHT, &inputs_right[device]);
00497             };break;
00498             case 12:
00499             {
00500               inputs_right[device].right = 
00501                (inputs_right[device].right == ON ? OFF : ON);
00502               ioctl(fd, MIXIOSETINPUTRIGHT, &inputs_right[device]);
00503             };break;
00504           }
00505           ioctl(fd, MIXIOGETINPUTLEFT, &inputs_left[device]);
00506           ioctl(fd, MIXIOGETINPUTRIGHT, &inputs_right[device]);
00507           show_inputs(41,8);
00508         }
00509       };break;
00510       case 's':
00511       {
00512         if (write_settings())  
00513           mvwprintw(main_win,22,28, "mixer settings saved");
00514         else
00515           mvwprintw(main_win,22,28, "error: file not saved");
00516         wrefresh(main_win);
00517         sleep(1);
00518         mvwprintw(main_win,22,28, "                           ");
00519       };break;
00520       case 'r':
00521       {
00522         if (read_settings())
00523           mvwprintw(main_win,22,28, "mixer settings restored");
00524         else
00525           mvwprintw(main_win,22,28, "error: could not open");
00526         wrefresh(main_win);
00527         sleep(1);
00528         setup_screen();
00529       };break;
00530       case 'e': terminate(1);
00531     }
00532   } 
00533 }
00534 
00535 
00536 char *d_name(device, name)
00537 enum Device device;
00538 char *name;
00539 {
00540   /* Convert the device number to a name */
00541 
00542   switch (device)
00543   {
00544     case Master:        strncpy(name, "Master  \0", 9);break;
00545     case Dac:           strncpy(name, "Dac     \0", 9);break;
00546     case Fm:            strncpy(name, "Fm      \0", 9);break;
00547     case Cd:            strncpy(name, "CD      \0", 9);break;
00548     case Line:          strncpy(name, "Line    \0", 9);break;
00549     case Mic:           strncpy(name, "Mic     \0", 9);break;
00550     case Speaker:       strncpy(name, "Speaker \0", 9);break;
00551     case Treble:        strncpy(name, "Treble  \0", 9);break;
00552     case Bass:          strncpy(name, "Bass    \0", 9);break;
00553   }
00554   return name;
00555 }
00556 
00557 
00558 void create_slider(x, y, device)
00559 int x;
00560 int y;
00561 enum Device device;
00562 {
00563   /* Create a slider on the screen */
00564 
00565   int left;
00566   int right;
00567   int i;
00568 
00569   mvwprintw(main_win,y,x, "%s", d_name(device, name));
00570 
00571   left = levels[device].left / (device < Speaker ? 2 : 1); 
00572   right = levels[device].right / (device < Speaker ? 2 : 1); 
00573 
00574   for (i = 0; i < 16; i++)
00575   {
00576     if (device != Speaker || i < 4)
00577       mvwprintw(main_win,y,x+i+8, (i == left ? "*" : "-"));
00578     if (device < Mic || device > Speaker) 
00579       mvwprintw(main_win,y+1,x+i+8, (i == right ? "*" : "-"));
00580   }
00581 
00582   if (device < Mic || device > Speaker)
00583   {
00584     mvwprintw(main_win,y,x+i+10, "left");
00585     mvwprintw(main_win,y+1,x+i+10, "right");
00586   }
00587   wrefresh(main_win);
00588 } 
00589   
00590 void show_inputs(x,y)
00591 int x;
00592 int y;
00593 {
00594   /* Show the input settings */
00595 
00596   int i;
00597 
00598   mvwprintw(main_win,y,x,  "             Rec-In  ");
00599   mvwprintw(main_win,y+1,x,"          left    right");
00600   mvwprintw(main_win,y+2,x,"          l   r   l   r");
00601   for (i = Fm; i <= Line; i++)
00602   {
00603     mvwprintw(main_win,y+i+1,x,  "%s  %d   %d   %d   %d", 
00604       d_name(i, (char *)name),
00605       (inputs_left[i].left == ON ? 1 : 0),
00606       (inputs_left[i].right == ON ? 1 : 0),
00607       (inputs_right[i].left == ON ? 1 : 0),
00608       (inputs_right[i].right == ON ? 1 : 0));
00609   }
00610   mvwprintw(main_win,y+i+1,x,  "%s    %d       %d", 
00611     d_name(Mic, (char *)name),
00612     (inputs_left[Mic].left == ON ? 1 : 0),
00613     (inputs_right[Mic].left == ON ? 1 : 0));
00614   wrefresh(main_win);
00615 }
00616 
00617 void show_outputs(x,y)
00618 int x;
00619 int y;
00620 {
00621   /* Show the output settings */
00622 
00623   int i;
00624 
00625   mvwprintw(main_win,y,x,      "            Mix-Out  ");
00626   mvwprintw(main_win,y+1,x,    "          left    right");
00627   for (i = Cd; i <= Line; i++)
00628   {
00629     mvwprintw(main_win,y+i-1,x,"%s    %d       %d", 
00630       d_name(i, (char *)name),
00631       (outputs[i].left == ON ? 1 : 0),
00632       (outputs[i].right == ON ? 1 : 0));
00633   }
00634   mvwprintw(main_win,y+i-1,x,"%s        %d", 
00635     d_name(Mic, (char *)name),
00636     (outputs[Mic].left == ON ? 1 : 0));
00637 
00638   wrefresh(main_win);
00639 }
00640 
00641 
00642 void setup_screen()
00643 {
00644   int i;
00645 
00646   wclear(main_win);
00647   mvwprintw(main_win,0,23,"------- Mixer Controls -------");
00648   wrefresh(main_win);
00649  
00650   for(i = 0; i <= Speaker; i++)
00651    create_slider(1, i*3+(i <= Mic ? 2 : 1), i);
00652 
00653    create_slider(40, 2, Treble);
00654    create_slider(40, 5, Bass);
00655  
00656    show_inputs(41,8);
00657    show_outputs(41,16);
00658 }

Generated on Fri Apr 14 22:56:57 2006 for minix by  doxygen 1.4.6