[xiph-cvs] cvs commit: MTG soundboard.c

Monty xiphmont at xiph.org
Fri Feb 1 03:20:55 PST 2002



xiphmont    02/02/01 03:20:55

  Modified:    .        soundboard.c
  Log:
  mostly functional at this point

Revision  Changes    Path
1.3       +498 -64   MTG/soundboard.c

Index: soundboard.c
===================================================================
RCS file: /usr/local/cvsroot/MTG/soundboard.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- soundboard.c	2002/01/31 10:43:23	1.2
+++ soundboard.c	2002/02/01 11:20:54	1.3
@@ -2,9 +2,9 @@
 
    make Esc behavior correct in editing menus by using temp cue/tag storage
    tag list menu
-
+   proper locking around edit to prevent playback problems
 */
-
+#define _REENTRANT 1
 #include <stdlib.h>
 #include <unistd.h>
 #include <stdio.h>
@@ -13,6 +13,8 @@
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <sys/time.h>
+#define __USE_GNU 1
 #include <pthread.h>
 #include <string.h>
 #include <math.h>
@@ -20,6 +22,8 @@
 #include <curses.h>
 #include <fcntl.h>
 
+#include <sys/soundcard.h>
+#include <sys/ioctl.h>
 
 #define int16 short
 static char *tempdir="/tmp/beaverphonic/";
@@ -30,10 +34,10 @@
 
 enum menutype {MENU_MAIN,MENU_KEYPRESS,MENU_ADD,MENU_EDIT,MENU_OUTPUT,MENU_QUIT};
 
-pthread_mutex_t master_mutex=PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t master_mutex=PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
 static long main_master_volume=50;
 char *program;
-static int playback_buffer_minfill=-1;
+static int playback_buffer_minfill=0;
 static int running=1;
 static enum menutype menu=MENU_MAIN;
 static int cue_list_position=0;
@@ -41,6 +45,17 @@
 static int firstsave=0;
 static int unsaved=0;
 
+static FILE *audiofd=NULL;
+int ttyfd;
+int ttypipe[2];
+
+
+pthread_t main_thread_id;
+pthread_t playback_thread_id;
+pthread_t tty_thread_id;
+
+void main_update_tags(int y);
+
 void *m_realloc(void *in,int bytes){
   if(!in)
     return(malloc(bytes));
@@ -63,10 +78,18 @@
   refresh();                 /* restore save modes, repaint screen */
 }
 
+int mgetch(){
+  while(1){
+    int ret=getch();
+    if(ret>0)return(ret);
+  }
+}
+
 /******** channel mappings.  All hardwired for now... ***********/
 // only OSS stereo builin for now
 #define MAX_CHANNELS 2
 #define CHANNEL_LABEL_LENGTH 50
+int playback_bufsize=0;
 
 typedef struct {
   char label[CHANNEL_LABEL_LENGTH];
@@ -207,6 +230,8 @@
   
   long   sample_position;
   long   sample_lapping;
+  long   sample_loop_start;
+  long   sample_fade_start;
 
   double master_vol_current;
   double master_vol_target;
@@ -317,7 +342,7 @@
     }
     
     t->channels=head.channels;
-    t->samplelength=length/(t->channels*2);
+    t->samplelength=(length-sizeof(head))/(t->channels*2);
 
     /* mmap the sample file */
     fprintf(stderr,"\tmmaping...\n");
@@ -363,10 +388,13 @@
 
 int edit_tag(int number,tag t){
   int ret;
-  tag *tag;
+  int refcount;
   _alloc_tag_if_needed(number);
+
+  refcount=tag_list[number].refcount;
   
   tag_list[number]=t;
+  tag_list[number].refcount=refcount;
 
   /* state is zeroed when we go to production mode.  Done  */
   return(0);
@@ -572,10 +600,12 @@
     addnlstr("LOAD ERROR (CUE): too few fields.",80,' ');
     return(-1);
   }
-  if(c.tag>=tag_count ||
-     !tag_list[c.tag].basemap){
-    addnlstr("LOAD ERROR (CUE): references a bad TAG",80,' ');
-    return(-1);
+  if(c.tag!=-1){
+    if(c.tag>=tag_count ||
+       !tag_list[c.tag].basemap){
+      addnlstr("LOAD ERROR (CUE): references a bad TAG",80,' ');
+      return(-1);
+    }
   }
 
   for(i=0;i<maxchannels;i++){
@@ -671,7 +701,7 @@
   }
 
   attroff(A_BOLD);
-  if(ret)getch();
+  if(ret)mgetch();
   return(ret);
 }
    
@@ -684,6 +714,306 @@
   return ret;
 }
 
+/*************** threaded playback ****************************/
+
+static inline double _slew_ms(long ms,double now,double target){
+
+  return((target-now)/(ms*44.1));
+  
+}
+
+/* position in active list */
+static inline void _playback_remove(int i){
+  tag *t=active_list[i];
+  t->activep=0;
+  refresh();
+  active_count--;
+  if(i<active_count)
+    memmove(active_list+i,
+	    active_list+i+1,
+	    (active_count-i)*sizeof(*active_list));
+  write(ttypipe[1],"",1);
+}
+
+/* position in tag list */
+static inline void _playback_add(int tagnum,int cuenum){
+  tag *t=tag_list+tagnum;
+  cue *c=cue_list+cuenum;
+  int j,k;
+
+  if(t->activep)return;
+  t->activep=1;
+  refresh();
+
+  active_list[active_count]=t;
+  active_count++;
+  t->sample_position=0;
+  t->sample_lapping=t->loop_lapping*44.1;
+  if(t->sample_lapping>(t->samplelength-t->sample_loop_start)/2)
+    t->sample_lapping=(t->samplelength-t->sample_loop_start)/2;
+  t->sample_lapping=t->samplelength-t->sample_lapping;
+
+  t->sample_loop_start=t->loop_start*44.1;
+  if(t->sample_loop_start>t->samplelength)
+    t->sample_loop_start=t->samplelength;
+
+  t->sample_fade_start=t->samplelength-t->fade_out*44.1;
+  if(t->sample_fade_start<0)t->sample_fade_start=0;
+  t->master_vol_current=0;
+
+  t->master_vol_target=c->mix.vol_master;
+  t->master_vol_slew=_slew_ms(c->mix.vol_ms,0,c->mix.vol_master);
+  			   
+  for(j=0;j<MAX_CHANNELS;j++)
+    for(k=0;k<t->channels;k++){
+      t->outvol_current[k][j]=0;
+      t->outvol_target[k][j]=c->mix.outvol[k][j];
+      t->outvol_slew[k][j]=_slew_ms(c->mix.vol_ms,0,c->mix.outvol[k][j]);
+    }
+  write(ttypipe[1],"",1);
+}
+
+/* position in tag list */
+static inline void _playback_mix(int i,int cuenum){
+  tag *t=tag_list+i;
+  cue *c=cue_list+cuenum;
+  int j,k;
+
+  if(!t->activep)return;
+
+  t->master_vol_target=c->mix.vol_master;
+  t->master_vol_slew=_slew_ms(c->mix.vol_ms,t->master_vol_current,
+			   c->mix.vol_master);
+  			   
+  for(j=0;j<MAX_CHANNELS;j++)
+    for(k=0;k<t->channels;k++){
+      t->outvol_target[k][j]=c->mix.outvol[k][j];
+      t->outvol_slew[k][j]=_slew_ms(c->mix.vol_ms,t->outvol_current[k][j],
+				 c->mix.outvol[k][j]);
+    }
+}
+
+static inline void _next_sample(int16 *out){
+  int i,j,k;
+  int staging[MAX_CHANNELS];
+
+  memset(staging,0,sizeof(staging));
+
+  /* iterate through the active sample list */
+  for(i=active_count-1;i>=0;i--){
+    tag *t=active_list[i];
+    for(j=0;j<t->channels;j++){
+      double value;
+      int lappoint=t->samplelength-t->sample_lapping;
+
+      /* get the base value, depending on loop or no */
+      if(t->loop_p && t->sample_position>=lappoint){
+	long looppos=t->sample_position-lappoint+t->sample_loop_start;
+	double value2=t->data[looppos*t->channels+j];
+	value=t->data[t->sample_position*t->channels+j];
+	
+	value=(value2*looppos/t->sample_lapping+
+	  value-value*looppos/t->sample_lapping)*t->master_vol_current*.01;
+
+      }else{
+	value=t->data[t->sample_position*t->channels+j]*
+	  t->master_vol_current*.01;
+      }
+
+      /* output split and mix */
+      for(k=0;k<MAX_CHANNELS;k++){
+	staging[k]+=value*t->outvol_current[j][k]*main_master_volume*.0001;
+	
+	t->outvol_current[j][k]+=t->outvol_slew[j][k];
+	if(t->outvol_slew[j][k]>0 && 
+	   t->outvol_current[j][k]>t->outvol_target[j][k]){
+	  t->outvol_slew[j][k]=0;
+	  t->outvol_current[j][k]=t->outvol_target[j][k];
+	}
+	t->outvol_current[j][k]+=t->outvol_slew[j][k];
+	if(t->outvol_slew[j][k]<0 && 
+	   t->outvol_current[j][k]<t->outvol_target[j][k]){
+	  t->outvol_slew[j][k]=0;
+	  t->outvol_current[j][k]=t->outvol_target[j][k];
+	}
+      }
+    }
+
+    /* update master volume */
+    t->master_vol_current+=t->master_vol_slew;
+    if(t->master_vol_slew>0 && t->master_vol_current>t->master_vol_target){
+      t->master_vol_slew=0;
+      t->master_vol_current=t->master_vol_target;
+    }
+    if(t->master_vol_slew<0 && t->master_vol_current<t->master_vol_target){
+      t->master_vol_slew=0;
+      t->master_vol_current=t->master_vol_target;
+    }
+    if(t->master_vol_current==0)
+      _playback_remove(i);
+    
+    /* determine if fade out has begun */
+    if(t->sample_position==t->sample_fade_start){
+      /* effect a master volume slew *now* */
+      t->master_vol_slew=_slew_ms(t->fade_out,
+				  t->master_vol_current,0);
+      t->master_vol_target=0;
+    }
+
+    /* update playback position */
+    t->sample_position++;
+    if(t->sample_position>=t->samplelength){
+      if(t->loop_p){
+	t->sample_position=t->sample_loop_start;
+      }else{
+	_playback_remove(i);
+      }
+    }
+
+  }
+
+  /* declipping, conversion */
+  for(i=0;i<MAX_CHANNELS;i++){
+    if(channel_list[i].peak<fabs(staging[i]))
+      channel_list[i].peak=fabs(staging[i]);
+    if(staging[i]>32767.){
+      out[i]=32767;
+    }else if(staging[i]<-32768.){
+      out[i]=-32768;
+    }else
+      out[i]=rint(staging[i]);
+  }
+}
+
+static int playback_active=0;
+static int playback_exit=0;
+
+void *playback_thread(void *dummy){
+  /* sound device startup */
+  audio_buf_info info;
+  int fd=fileno(audiofd),i;
+  int format=AFMT_S16_NE;
+  int stereo=1;
+  int rate=44100;
+  long last=0;
+  long delay=10;
+  long totalsize;
+  int fragment=0x7fff000d;
+  int16 audiobuf[256];
+
+  ioctl(fd,SNDCTL_DSP_SETFRAGMENT,&fragment);
+  ioctl(fd,SNDCTL_DSP_SETFMT,&format);
+  ioctl(fd,SNDCTL_DSP_STEREO,&stereo);
+  ioctl(fd,SNDCTL_DSP_SPEED,&rate);
+
+  ioctl(fd,SNDCTL_DSP_GETOSPACE,&info);
+  totalsize=info.fragstotal*info.fragsize;
+
+  while(!playback_exit){
+    int samples;
+
+    pthread_mutex_lock(&master_mutex);
+    delay--;
+    if(delay<0){
+      delay=0;
+      ioctl(fd,SNDCTL_DSP_GETOSPACE,&info);
+      playback_bufsize=totalsize;      
+      samples=playback_bufsize-info.bytes;
+      
+      if(playback_buffer_minfill>samples)
+	playback_buffer_minfill=samples;
+    }
+
+    for(i=0;i<256;i+=2)
+      _next_sample(audiobuf+i);
+    fwrite(audiobuf,2,256,audiofd);
+    
+    pthread_mutex_unlock(&master_mutex);
+    
+    {
+      struct timeval tv;
+      long foo;
+      gettimeofday(&tv,NULL);
+      foo=tv.tv_sec*2+tv.tv_usec/500000;
+      if(last!=foo)
+	write(ttypipe[1],"",1);
+      last=foo;
+    }
+
+  }
+  
+  playback_active=0;
+  
+  /* sound device shutdown */
+  
+  ioctl(fd,SNDCTL_DSP_RESET);
+  pthread_mutex_unlock(&master_mutex);
+  return(NULL);
+}
+
+/* cuenum is the base number */ 
+int play_cue(int cuenum){
+  pthread_mutex_lock(&master_mutex);
+  while(1){
+    cue *c=cue_list+cuenum;
+    if(c->tag>=0){
+      if(c->tag_create_p)
+	_playback_add(c->tag,cuenum);
+      else
+	_playback_mix(c->tag,cuenum);
+    }
+    cuenum++;
+    if(cuenum>=cue_count || cue_list[cuenum].tag==-1)break;
+  }
+  /* is a playback thread running? */
+  if(!playback_active){
+    pthread_t dummy;
+    pthread_create(&playback_thread_id,NULL,playback_thread,NULL);
+    playback_active=1;
+  }
+  pthread_mutex_unlock(&master_mutex);
+  return(0);
+}
+
+int play_sample(int cuenum){
+  cue *c=cue_list+cuenum;
+  pthread_mutex_lock(&master_mutex);
+  if(c->tag>=0){
+    if(c->tag_create_p)
+      _playback_add(c->tag,cuenum);
+      else
+	_playback_mix(c->tag,cuenum);
+  }
+  
+  /* is a playback thread running? */
+  if(!playback_active){
+    pthread_t dummy;
+    pthread_create(&playback_thread_id,NULL,playback_thread,NULL);
+    playback_active=1;
+  }
+  pthread_mutex_unlock(&master_mutex);
+  return(0);
+}
+
+int halt_playback(){
+  int i;
+  pthread_mutex_lock(&master_mutex);
+  for(i=0;i<tag_count;i++){
+    tag *t=tag_list+i;
+    int j,k;
+
+    if(t->activep){
+
+      t->master_vol_target=0;
+      t->master_vol_slew=_slew_ms(100,t->master_vol_current,0);
+      
+    }
+  }
+  pthread_mutex_unlock(&master_mutex);
+  return(0);
+}
+
+
 /***************** simple form entry fields *******************/
 
 enum field_type { FORM_YESNO, FORM_PERCENTAGE, FORM_NUMBER, FORM_GENERIC,
@@ -920,11 +1250,11 @@
         {
           int *val=(int *)ff->var;
           switch(c){
-	  case '+':case '=':case KEY_LEFT:
+	  case '+':case '=':case KEY_RIGHT:
             (*val)++;
             if(*val>100)*val=100;
             break;
-	  case '-':case '_':case KEY_RIGHT:
+	  case '-':case '_':case KEY_LEFT:
             (*val)--;
             if(*val<0)*val=0;
             break;
@@ -1050,17 +1380,27 @@
     char buf[20];
     int  n;
     static int starve=0;
-    
+
     pthread_mutex_lock(&master_mutex);
     n=playback_buffer_minfill;
+    playback_buffer_minfill=playback_bufsize;
     pthread_mutex_unlock(&master_mutex);
     
-    if(n==0)starve=1;
-    if(n<0){
+    if(n==0){
+      starve=15;
+    }
+    starve--;
+    if(starve<0){
       starve=0; /* reset */
-      n=0;
     }
     
+    if(playback_bufsize)
+      n=rint(100.*n/playback_bufsize);
+    else{
+      n=0;
+      starve=0;
+    }
+
     move(y,4);
     addstr("playbuffer: ");
     sprintf(buf,"%3d%% %s",n,starve?"***STARVE***":"            ");
@@ -1069,7 +1409,7 @@
 }
 
 #define todB_nn(x)   ((x)==0.f?-400.f:log((x))*8.6858896f)
-
+static int clip[MAX_CHANNELS];
 void main_update_outchannel_levels(int y){
   int i,j;
   if(menu==MENU_MAIN){
@@ -1078,10 +1418,17 @@
       char buf[11];
       pthread_mutex_lock(&master_mutex);
       val=channel_list[i].peak;
+      channel_list[i].peak=0;
       pthread_mutex_unlock(&master_mutex);
-
+      
       move(y+i+1,24);
       if(val>=32767){
+	clip[i]=15;
+	val=32767;
+      }
+      clip[i]--;
+      if(clip[i]<0)clip[i]=0;
+      if(clip[i]){
         attron(A_BOLD);
         addstr("CLIP");
       }else{
@@ -1173,8 +1520,11 @@
 void main_update_tags(int y){
   if(menu==MENU_MAIN){
     int i;
+    static int last_tags=0;
 
     move(y,0);
+    
+    pthread_mutex_lock(&master_mutex);
     if(active_count){
       int len;
       addstr("playing tags:");
@@ -1186,10 +1536,9 @@
         label_number path;
         
         move(y+i,14);
-	/* normally called by playback so no locking */
         loop=active_list[i]->loop_p;
-	ms=active_list[i]->samplelength-active_list[i]->sample_position;
-	path=active_list[i]->sample_path;
+	ms=(active_list[i]->samplelength-active_list[i]->sample_position)/44.1;
+	path=active_list[i]->sample_desc;
         
         if(loop)
           sprintf(buf,"[loop] ");
@@ -1198,13 +1547,17 @@
         addstr(buf);
         addnlstr(label_text(path),55,' ');
       }
-      move(y+i,14);
-      addnlstr("",55,' ');
     }else{
       addstr("             ");
-      move(y,14);
+    }
+
+    for(i=active_count;i<last_tags;i++){
+      move(y+i,14);
       addnlstr("",55,' ');
     }
+
+    last_tags=active_count;
+    pthread_mutex_unlock(&master_mutex);
   }
 }
 
@@ -1300,7 +1653,6 @@
   move(2,7);
   addstr(" output ");
 
-
   mvhline(9+MAX_CHANNELS,0,0,80);
   mvhline(18+MAX_CHANNELS,0,0,80);
 
@@ -1325,14 +1677,14 @@
       addnlstr("Really quit? [y/N] ",80,' ');
       attroff(A_BOLD);
       refresh();
-      ch=getch();
+      ch=mgetch();
       if(ch=='y'){
         if(unsaved){
           move(0,0);
           attron(A_BOLD);
           addnlstr("Save changes first? [Y/n] ",80,' ');
           attroff(A_BOLD);
-	  ch=getch();
+	  ch=mgetch();
           if(ch!='n' && ch!='N')save_top_level(program);
         }
         return(MENU_QUIT);
@@ -1352,13 +1704,13 @@
       break;
     case 'd':
       if(editable){
-	//halt_playback();
+	halt_playback();
         move(0,0);
         attron(A_BOLD);
         addnlstr("Really delete cue? [y/N] ",80,' ');
         attroff(A_BOLD);
         refresh();
-	ch=getch();
+	ch=mgetch();
         if(ch=='y'){
           unsaved=1;
           delete_cue_bank(cue_list_number);
@@ -1378,7 +1730,7 @@
       break;
     case 's':
       save_top_level(program);
-      getch();
+      mgetch();
       return(MENU_MAIN);
     case '-':case '_':
       unsaved=1;
@@ -1389,7 +1741,7 @@
       main_update_master(main_master_volume+1,5);
       break;
     case ' ':
-      //run_next_cue();
+      play_cue(cue_list_number);
       move_next_cue();
       break;
     case KEY_UP:case '\b':case KEY_BACKSPACE:
@@ -1399,10 +1751,10 @@
       move_next_cue();
       break;
     case 'H':
-      //halt_playback();
+      halt_playback();
       break;
     case 'R':
-      //halt_playback();
+      halt_playback();
       cue_list_position=0;
       cue_list_number=0;
       return(MENU_MAIN);
@@ -1412,6 +1764,11 @@
       else
         editable=1;
       update_editable();
+    case 0:
+      main_update_tags(19+MAX_CHANNELS);
+      main_update_playbuffer(4);
+      main_update_outchannel_labels(7);
+      break;
     }
   }
 }
@@ -1453,7 +1810,7 @@
 
   mvaddstr(19,12,"any key to return to main menu");
   refresh();
-  getch();
+  mgetch();
   return(MENU_MAIN);
 }
 
@@ -1483,7 +1840,7 @@
   refresh();
   
   while(1){
-    int ch=form_handle_char(&f,getch());
+    int ch=form_handle_char(&f,mgetch());
     switch(ch){
     case KEY_ENTER:case 'x':case 'X':
       goto enter;
@@ -1535,6 +1892,8 @@
   mvaddstr(9,2, "        d");
   mvaddstr(10,2,"    enter");
   mvaddstr(11,2,"        l");
+  mvaddstr(12,2,"    space");
+  mvaddstr(12,2,"        H");
 
   attroff(A_BOLD);
   mvaddstr(2,12,"keypress menu (you're there now)");
@@ -1546,10 +1905,12 @@
   mvaddstr(9,12,"delete highlighted action");
   mvaddstr(10,12,"edit highlighted action");
   mvaddstr(11,12,"list all samples and sample tags");
+  mvaddstr(12,12,"play cue");
+  mvaddstr(13,12,"halt playback");
 
-  mvaddstr(13,12,"any key to return to cue edit menu");
+  mvaddstr(15,12,"any key to return to cue edit menu");
   refresh();
-  getch();
+  mgetch();
 }
 
 void edit_sample_menu(int n){
@@ -1656,6 +2017,12 @@
     int ch=form_handle_char(&f,getch());
     
     switch(ch){
+    case ' ':
+      play_sample(n);
+      break;
+    case 'H':
+      halt_playback();
+      break;
     case 27:
       goto out;
     case 'x':case 'X':case KEY_ENTER:
@@ -1796,7 +2163,7 @@
   form_redraw(&f);
 
   while(1){
-    int ch=getch();
+    int ch=mgetch();
     int re=form_handle_char(&f,ch);
 
     if(re>=0 || !f.edit){
@@ -1804,19 +2171,21 @@
         form_clear(&f);
         return(MENU_EDIT);
       }
-      break;
-    }
-  }
 
-  /* try to load the sample! */
-  switch_to_stderr();
-  if(load_sample(&t,path)){
-    fprintf(stderr,"Press enter to continue\n");
-    getc(stdin);
-    switch_to_ncurses();
-    return(1);
+      /* try to load the sample! */
+      switch_to_stderr();
+      memset(&t,0,sizeof(t));
+      if(load_sample(&t,path)){
+	fprintf(stderr,"Press enter to continue\n");
+	getc(stdin);
+	switch_to_ncurses();
+
+      }else{
+	switch_to_ncurses();
+	break;
+      }
+    }
   }
-  switch_to_ncurses();
 
   unsaved=1;
 
@@ -1886,7 +2255,7 @@
   addstr("' for a list of sample tags                    ");
 
   while(1){
-    int ch=getch();
+    int ch=mgetch();
     int re=form_handle_char(&f,ch);
 
     if(re>=0 || !f.edit){
@@ -1896,7 +2265,7 @@
       }
       if(tagno>=tag_count || tag_list[tagno].refcount<=0){
         mvaddstr(4,2,"Bad tag number; any key to continue.");
-	getch();
+	mgetch();
         mvaddstr(4,2,"'");
         attron(A_BOLD);
         addstr("l");
@@ -1986,7 +2355,7 @@
     form_redraw(&f);
     
     while(loop){
-      int ch=form_handle_char(&f,getch());
+      int ch=form_handle_char(&f,mgetch());
       
       switch(ch){
       case '?':case '/':
@@ -2024,6 +2393,12 @@
         //list_tag_menu();
         loop=0;
         break;
+      case ' ':
+	play_cue(cue_list_number);
+	break;
+      case 'H':
+	halt_playback();
+	break;
       case KEY_ENTER:
         if(f.cursor==3+actions){
           unsaved=1;
@@ -2072,13 +2447,25 @@
       menu=menu_output();
       break;
     case MENU_EDIT:
-      //halt_playback();
+      halt_playback();
       menu=edit_cue_menu();
       break;
     }
   }
 }
-  
+
+pthread_mutex_t pipe_mutex=PTHREAD_MUTEX_INITIALIZER;
+
+void *tty_thread(void *dummy){
+  char buf;
+
+  while(!playback_exit){
+    int ret=read(ttyfd,&buf,1);
+    if(ret==1)
+      write(ttypipe[1],&buf,1);
+  }
+}
+
 int main(int gratuitously,char *different[]){
   int lf;
 
@@ -2102,31 +2489,78 @@
     exit(1);
   }
 
+  audiofd=fopen("/dev/dsp","wb");
+  if(!audiofd){
+    fprintf(stderr,"unable to open audio device: %s.\n",strerror(errno));
+    fprintf(stderr,"\nPress enter to continue\n");
+    getc(stdin);
+  }
+
+  /* set up the hack for interthread ncurses event triggering through
+   input subversion */
+  ttyfd=open("/dev/tty",O_RDONLY);
+  if(ttyfd<0){
+    fprintf(stderr,"Unable to open /dev/tty:\n"
+	    "  %s\n",strerror(errno));
+    
+    exit(1);
+  }
+  if(pipe(ttypipe)){
+    fprintf(stderr,"Unable to open tty pipe:\n"
+	    "  %s\n",strerror(errno));
+    
+    exit(1);
+  }
+  dup2(ttypipe[0],0);
+  pthread_create(&tty_thread_id,NULL,tty_thread,NULL);
+  
+
+
+
+
+
   /* load the sound config if the file exists, else create it */
+  initscr(); cbreak(); noecho();
+  nonl();
+  intrflush(stdscr, FALSE);
+  keypad(stdscr, TRUE);
+  use_default_colors();
+  signal(SIGINT,SIG_IGN);
+  
+  clear();
+  switch_to_stderr();
   program=strdup(different[1]);
   {
     FILE *f=fopen(program,"rb");
     if(f){
       if(load_program(f)){
-	fprintf(stderr,"Press enter to continue\n");
+	fprintf(stderr,"\nPress enter to continue\n");
         getc(stdin);
       }
       fclose(f);
     }
   }
-
+  switch_to_ncurses();
 
-  initscr(); cbreak(); noecho();
-  nonl();
-  intrflush(stdscr, FALSE);
-  keypad(stdscr, TRUE);
-  use_default_colors();
-  signal(SIGINT,SIG_IGN);
+  main_thread_id=pthread_self();
 
-  
   main_loop();
   endwin();                  /* restore original tty modes */  
   close(lf);
+  halt_playback();
+  pthread_mutex_lock(&master_mutex);
+  playback_exit=1;
+  pthread_mutex_unlock(&master_mutex);
+
+  while(1){
+    pthread_mutex_lock(&master_mutex);
+    if(!playback_active)break;
+    sched_yield();
+    pthread_mutex_unlock(&master_mutex);
+  }
+  pthread_mutex_unlock(&master_mutex);
+  fclose(audiofd);
+
   unlink(lockfile);
 }  
 

<p><p><p>--- >8 ----
List archives:  http://www.xiph.org/archives/
Ogg project homepage: http://www.xiph.org/ogg/
To unsubscribe from this list, send a message to 'cvs-request at xiph.org'
containing only the word 'unsubscribe' in the body.  No subject is needed.
Unsubscribe messages sent to the list will be ignored/filtered.



More information about the commits mailing list