/* 
   CAM - Cpu's Audio Mixer for Linux  
  
   AUTHOR: Jan 'TWP' VANDENBERGHE (jvdbergh@wins.uia.ac.be) 
*/ 
  
/*    
     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 <fcntl.h> 
#include <unistd.h> 
#include <sys/ioctl.h> 
#include <sys/soundcard.h> 
#include <ncurses.h> 
#include <string.h> 
 
#include "screens.h" 
#include "sounds.h" 
 
 
/* global variables */ 
int devmask = 0, recmask = 0, recsrc = 0, stereodevs = 0, mixer_fd; 
char *devname[DEV_COUNT] = SOUND_DEVICE_LABELS; 
int  dev_vol[DEV_COUNT][2] ,dev_nr = 0; 
 
 
/* Gives a volume to a device */ 
void Adjust(int temp[2],int dev_nr) 
{ 
  int temp_0,temp_1, temp2; 
  temp_0 = temp[0] * 1285 ; 
  temp_1 = temp[1] * 1285; 
  temp_0 =  getbits(temp_0,7,8); 
  temp_1 = getbits(temp_1,15,8) << 8; 
  temp2 = temp_1 + temp_0; 
  if (ioctl(mixer_fd, MIXER_WRITE(dev_nr), &temp2) == -1) 
  { 
     stop();
     perror("MIXER_WRITE : Can't write to /dev/mixer !"); 
     exit(-1); 
  } 
 
} 

/* evaluates an argument */ 
int eval_argv(char *arg) 
{ 
   if ( strcmp(arg,"-v") == 0) 
      return 0; 
   else if ( strcmp(arg,"-b") == 0) 
	return 1; 
   else if ( strcmp(arg,"-t") == 0) 
        return 2; 
   else if ( strcmp(arg,"-s") == 0) 
        return 3; 
   else if ( strcmp(arg,"-p") == 0) 
        return 4; 
   else if ( strcmp(arg,"-S") == 0) 
        return 5; 
   else if ( strcmp(arg,"-l") == 0) 
	return 6; 
   else if ( strcmp(arg,"-m") == 0) 
        return 7; 
   else if ( strcmp(arg,"-c") == 0) 
        return 8; 
   else if ( strcmp(arg,"-M") == 0) 
        return 9; 
   else if ( strcmp(arg,"-P") == 0) 
        return 10; 
   else if ( strcmp(arg,"-r") == 0) 
        return 11; 
   else if ( strcmp(arg,"-h") == 0) 
        return 12; 
   else if ( strcmp(arg,"-g") == 0) 
        return 13; 
   else  
      return 99; 
} 

/* sets sound given from command line */ 
void set_sound(int argc, char *argv[]) 
{ 
   int i,ii, temp_vol[2],dummy; 
   FILE *save_file; 
   for (i = 0; i < argc / 2; i++ ) 
   { 
       dev_nr = eval_argv(argv[(i*2)+1]); 
       switch (dev_nr) 
       { 
	  case 12 : 
	       comm_help(); 
	       break; 
	  case 13 : 
	       if (( save_file = fopen("/tmp/cam_vol.save","r")) == NULL) 
		  printf("\nNo save file available\n\n"); 
	       else 
	       { 
		  dev_nr = 0; 
		  fscanf(save_file,"%i %i",&dummy, &recsrc); 
		  if (ioctl(mixer_fd, SOUND_MIXER_WRITE_RECSRC, &recsrc) == -1) 
		  { 
		     perror("SOUND_MIXER_WRITE_RECSRC : Error writing /dev/mixer"); 
		     exit(-1); 
		  } 
 
		  for (ii = 0 ; ii < DEV_COUNT ; ii++) 
		  { 
		      fscanf(save_file,"%i %i ",&temp_vol[0], &temp_vol[1]); 
		      fflush(save_file); 
		      if (DEV_EXIST) 
			 Adjust(temp_vol,dev_nr); 
		      dev_nr++; 
		  } 
	       } 
	       break; 
	 default : 
	       if (STEREO ) 
		  sscanf(argv[(i*2)+2],"%i,%i",&temp_vol[0],&temp_vol[1]); 
	       else 
	       { 
		  sscanf(argv[(i*2)+2],"%i",&temp_vol[0]); 
		  temp_vol[1] = temp_vol[0]; 
	       } 
	       if ( ((temp_vol[0] > 0) && (temp_vol[0] <= 20)) &&  ((temp_vol[1] > 0) && (temp_vol[1] <= 20))) 
		  if (DEV_EXIST) 
		     Adjust(temp_vol,dev_nr); 
       } 
   } 
} 
 
/* controles the slidebars */ 
void ctrl_slide(void) 
{ 
  int ch, left = 0; 
  int locked = FALSE;  
  FILE *save_file; 
  int i, old_dev_nr; 
 
  for ( dev_nr = 0;!(DEV_EXIST); dev_nr++); 
  keypad(stdscr, TRUE); 
  cbreak(); 
  noecho(); 
  Draw_handle(4,1,left); 
  refresh(); 
  do 
  { 
     int was_stereo = STEREO; 
     status( ((locked  == TRUE) ? " LOCKED " : " UNLOCKED ")); 
     ch = wgetch(stdscr); 
     fflush(stdin); 
     message(""); 
     switch (ch) 
     { 
	case 27 : case 'q' : case 'Q' :
	     break; 
	case 'r' : case 'R' : 
	     if ( DEV_REC ) 
	     { 
	        if ( REC_ON ) 
		   recsrc &= ~(1 << dev_nr); 
		else 
		   recsrc |= (1 << dev_nr); 
                if (ioctl(mixer_fd, SOUND_MIXER_WRITE_RECSRC, &recsrc) == -1)  
                { 
		   stop();
                   perror("SOUND_MIXER_WRITE_RECSRC : Error writing /dev/mixer"); 
                   exit(-1); 
		} 
                if (REC_ON) 
		   attrset(COLOR_PAIR(COLOR_REC_ON) | A_ALTCHARSET | A_BOLD); 
                else 
                   attrset(COLOR_PAIR(COLOR_REC_OFF) | A_ALTCHARSET | A_BOLD); 
 
		mvaddch(Y_POS+1,X_POS - 10,254); 
	     } 
             break;   
        case KEY_LEFT :  
              
             if  (dev_vol[dev_nr][left] > 1) 
             { 
                 dev_vol[dev_nr][left]--; 
		 Draw_handle(2,1,left); 
		 if ( (locked) || !STEREO ) 
		 { 
		     dev_vol[dev_nr][(left+1)%2]--; 
                     if ( STEREO)     
	                Draw_handle(2,1,(left+1)%2); 
                 }   
             } 
             else if (dev_vol[dev_nr][left] == 1) 
                  { 
		     dev_vol[dev_nr][left]--; 
		     Draw_handle(1,1,left); 
		     if ( (locked) || !STEREO) 
		     { 
                        dev_vol[dev_nr][(left+1)%2]--; 
                        if ( STEREO )  
                           Draw_handle(1,1,(left+1)%2); 
		     } 
                  } 
	     break; 
	case KEY_RIGHT: 
             if (dev_vol[dev_nr][left] < 19) 
	     { 
                dev_vol[dev_nr][left]++; 
                Draw_handle(2,1,left); 
                if ( (locked)  || !STEREO ) 
	        {    
                   dev_vol[dev_nr][(left+1)%2]++; 
                   if ( STEREO ) 
                      Draw_handle(2,1,(left+1)%2); 
	        } 
	     } 
             else if (dev_vol[dev_nr][left] == 19 ) 
	          { 
	             dev_vol[dev_nr][left]++; 
		     Draw_handle(3,1,left); 
		     if ( (locked) || !STEREO ) 
		     { 
                        dev_vol[dev_nr][(left+1)%2]++; 
			if (STEREO) 
			   Draw_handle(3,1,(left+1)%2); 
		     } 
	          } 
	     break; 
	case KEY_UP: 
 
             Draw_handle(4,0,left); 
             if ( (locked) && STEREO) 
                Draw_handle(4,0,(left+1)%2); 
             if ((left == 0) || ( locked) || !STEREO ) 
	     { 
                do 
                   dev_nr  = (dev_nr+DEV_COUNT - 1) % DEV_COUNT ; 
                while (!(DEV_EXIST)); 
	     } 
 
             if ( locked ) 
	     { 
                int temp_vol; 
		Draw_handle(5,0,left); 
                if ((locked) && STEREO) 
                   Draw_handle(5,0,(left+1)%2); 
                temp_vol = (dev_vol[dev_nr][0] + dev_vol[dev_nr][1] ) / 2 ; 
                dev_vol[dev_nr][0] = temp_vol; 
                dev_vol[dev_nr][1] = temp_vol; 
 
	     } 
	     if ( ( (!locked) && STEREO ) || ((left == 1) && !STEREO) ) 
                left = (left + 1) % 2; 
             Draw_handle(4,1,left); 
             if ((locked) && STEREO) 
                Draw_handle(4,1,(left+1)%2); 
	      
	     break; 
 
	case KEY_DOWN: 
      
             Draw_handle(4,0,left); 
             if ((locked) && STEREO) 
                Draw_handle(4,0,(left+1)%2); 
 
             if ((left == 1) || (locked) || (!STEREO)) 
             { 
                do 
                    dev_nr = (dev_nr + 1) % DEV_COUNT; 
                while (!(DEV_EXIST)); 
	     } 
 
             if ( locked ) 
	     { 
	        int temp_vol; 
                Draw_handle(5,0,left); 
                if ((locked) && STEREO) 
                   Draw_handle(5,0,(left+1)%2); 
	        temp_vol = (dev_vol[dev_nr][0] + dev_vol[dev_nr][1] ) / 2 ; 
                dev_vol[dev_nr][0] = temp_vol; 
                dev_vol[dev_nr][1] = temp_vol; 
             }   
             if ( ((!locked) && was_stereo) || ( (left == 1) && !STEREO )) 
                left = (left + 1) % 2 ; 
	     Draw_handle(4,1,left);      
             if ((locked) && STEREO) 
                Draw_handle(4,1,(left+1)%2); 
	     break; 
           
	case 'l' : case 'L': 
      
             if ((locked) && STEREO ) 
                Draw_handle(4,0,(left+1) % 2);  
             else if  ((!locked) && STEREO ) 
	          { 
                      int temp_vol;   
                      Draw_handle(5,0,(left)); 
                      Draw_handle(5,0,(left+1)%2); 
 
                      temp_vol = (dev_vol[dev_nr][0] + dev_vol[dev_nr][1] )  / 2 ; 
		      dev_vol[dev_nr][0] = temp_vol; 
		      dev_vol[dev_nr][1] = temp_vol; 
		      Draw_handle(4,1,(left)); 
		      Draw_handle(4,1,(left+1)%2); 
                  } 
	     locked =  (locked+1) % 2; 
	     break; 
        
	case 's' : case 'S' : 
              
             if (( save_file = fopen("/tmp/cam_vol.save","w")) == NULL) 
	     { 
	        stop();
                perror("Error creating /tmp/cam_vol.save"); 
                exit(1); 
             } 
             fprintf(save_file,"%i %i ",locked,recsrc); 
             for (i = 0 ; i < DEV_COUNT ; i++) 
             { 
	         fprintf(save_file,"%i %i ",dev_vol[i][0], dev_vol[i][1]); 
                  
	     }  
	     fflush(save_file); 
	     message("Settings saved"); 
 
	     break;         
        case 'g': case 'G': 
 
             if (( save_file = fopen("/tmp/cam_vol.save","r")) == NULL) 
                message("No save file available"); 
             else 
	     {   
                old_dev_nr = dev_nr; 
                dev_nr = 0; 
		fscanf(save_file,"%i %i",&locked, &recsrc); 
		if (ioctl(mixer_fd, SOUND_MIXER_WRITE_RECSRC, &recsrc) == -1) 
		{ 
		   stop();
                   perror("SOUND_MIXER_WRITE_RECSRC : Error writing /dev/mixer"); 
		   exit(-1);
		} 
 
		for (i = 0 ; i < DEV_COUNT ; i++) 
                { 
		    if ( DEV_REC ) 
		    { 
                       if ( REC_ON ) 
                          attrset(COLOR_PAIR(COLOR_REC_ON) | A_ALTCHARSET | A_BOLD); 
                       else if (!REC_ON) 
                            attrset(COLOR_PAIR(COLOR_REC_OFF) | A_ALTCHARSET | A_BOLD); 
                       mvaddch(Y_POS+1,X_POS - 10,254); 
		    } 
 
		    if ( DEV_EXIST ) 
		    { 
		       Draw_handle(5,0,0); 
		       if ( STEREO ) 
                          Draw_handle(5,0,1); 
		    } 
		    fscanf(save_file,"%i %i ",&dev_vol[i][0], &dev_vol[i][1]); 
		    fflush(save_file); 
		    if (DEV_EXIST) 
		    {   
                       Draw_handle(4,( i == old_dev_nr ? 1 : 0 ), ( STEREO ? left : 0) ); 
                       if ( STEREO ) 
                          Draw_handle(4,( ((i == old_dev_nr ) && ( locked)) ? 1 : 0 ),(left + 1) % 2); 
                       Adjust(dev_vol[dev_nr],dev_nr);                  
		    } 
                    dev_nr = (dev_nr  + 1) % DEV_COUNT; 
                    refresh(); 
		} 
		dev_nr = old_dev_nr; 
                message("Settings loaded"); 
	     } 
             break;    
        case 'h': case 'H': 
             help(); 
             break;    
     } 
     if ( (ch != 27) && (ch != 'Q') &&  (ch != 'q') )  
     { 
        refresh(); 
        Adjust(dev_vol[dev_nr],dev_nr);   
     } 
   } 
   while ( (ch != 27) && (ch != 'Q') &&  (ch != 'q') ); 
   
} 
 
/* initializes the sound */ 
void init_sound() 
{ 
  if ((mixer_fd = open("/dev/mixer", O_RDWR)) < 0)  
  { 
     stop(); 
     perror("Error opening /dev/mixer. : you probably don't have an audiocard that supports a mixer"); 
     exit(1); 
  } 
  if (ioctl(mixer_fd, SOUND_MIXER_READ_DEVMASK, &devmask) == -1)  
  { 
    stop(); 
    perror("SOUND_MIXER_READ_DEVMASK : Error reading /dev/mixer"); 
    exit(-1); 
  } 
  if (ioctl(mixer_fd, SOUND_MIXER_READ_RECMASK, &recmask) == -1)  
  { 
    stop(); 
    perror("SOUND_MIXER_READ_RECMASK : Error reading /dev/mixer"); 
    exit(-1); 
  } 
  if (ioctl(mixer_fd, SOUND_MIXER_READ_RECSRC, &recsrc) == -1)  
  { 
    stop(); 
    perror("SOUND_MIXER_READ_RECSRC : Error reading /dev/mixer"); 
    exit(-1); 
  } 
  if (ioctl(mixer_fd, SOUND_MIXER_READ_STEREODEVS, &stereodevs) == -1)  
  { 
    stop(); 
    perror("SOUND_MIXER_READ_STEREODEVS : Error reading /dev/mixer"); 
    exit(-1); 
 
  } 
  if (!devmask)  
  { 
    stop(); 
    perror("No device found."); 
    exit(-1); 
  } 
} 
 
 
 
 
