[xiph-cvs] cvs commit: postfish output.c Makefile input.c input.h main.c mainpanel.c mainpanel.h postfish.h readout.h

Monty xiphmont at xiph.org
Sun Oct 12 23:01:23 PDT 2003



xiphmont    03/10/13 02:01:23

  Modified:    .        Makefile input.c input.h main.c mainpanel.c
                        mainpanel.h postfish.h readout.h
  Added:       .        output.c
  Log:
  Code reorg in progress to make pipeline work smoother.

Revision  Changes    Path
1.5       +2 -2      postfish/Makefile

Index: Makefile
===================================================================
RCS file: /usr/local/cvsroot/postfish/Makefile,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- Makefile	10 Oct 2003 21:45:44 -0000	1.4
+++ Makefile	13 Oct 2003 06:01:22 -0000	1.5
@@ -5,8 +5,8 @@
 CC=gcc
 LD=gcc
 
-SRC = main.c mainpanel.c multibar.c readout.c
-OBJ = main.o mainpanel.o multibar.o readout.o
+SRC = main.c mainpanel.c multibar.c readout.c input.c output.c
+OBJ = main.o mainpanel.o multibar.o readout.o input.o output.o
 GCF = `pkg-config --cflags gtk+-2.0`
 
 all:	

<p><p>1.2       +159 -405  postfish/input.c

Index: input.c
===================================================================
RCS file: /usr/local/cvsroot/postfish/input.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- input.c	12 Oct 2003 00:44:15 -0000	1.1
+++ input.c	13 Oct 2003 06:01:22 -0000	1.2
@@ -21,14 +21,21 @@
  * 
  */
 
+#include "postfish.h"
+
 static off_t        Acursor=0;
 static off_t        Bcursor=-1;
-static long         T=-1;
 static off_t        cursor=0;
-static int          rate;
-static sig_atomic_t loop_active;
 
-static typedef struct {
+sig_atomic_t loop_active;
+int seekable;
+
+static int input_rate;
+int input_ch;
+static int inbytes;
+static int signp;
+
+typedef struct {
   FILE *f;
   
   off_t begin;
@@ -41,31 +48,17 @@
 static int file_entries=0;
 static int current_file_entry_number=-1;
 static file_entry *current_file_entry=NULL;
-static int seekable=0;
-
-int input_seekablep(void){
-  return seekable;
-}
-
-int input_rate_get(void){
-  return rate;
-}
-
-void input_cursorA_set(off_t c){
-  pthread_mutex_lock(&master_mutex);
-  cursorA=c;
-  pthread_mutex_unlock(&master_mutex);
-}
+static time_linkage out;
 
-void input_cursorB_set(off_t c){
+void input_Acursor_set(off_t c){
   pthread_mutex_lock(&master_mutex);
-  cursorB=c;
+  Acursor=c;
   pthread_mutex_unlock(&master_mutex);
 }
 
-void input_cursor_set(off_t cr){
+void input_Bcursor_set(off_t c){
   pthread_mutex_lock(&master_mutex);
-  cursor=c;
+  Bcursor=c;
   pthread_mutex_unlock(&master_mutex);
 }
 
@@ -147,7 +140,6 @@
 }
 
 void input_cursor_to_time(off_t cursor,char *t){
-  char 
   int h=cursor/60/60/100,m,s,hd;
   cursor%=(off_t)60*60*100;
   m=cursor/60/100;
@@ -160,357 +152,35 @@
   time_fix(t);
 }
 
-
-int aseek(off_t pos){
-  int i;
-
-  if(pos<0)pos=0;
-  if(!seekable){
-    current_file_entry=file_list;
-    current_file_entry_number=0;
-    return -1;
-  }
-
-  pthread_mutex_lock(&master_mutex);
-  for(i=0;i<file_entries;i++){
-    current_file_entry=file_list+i;
-    current_file_entry_number=i;
-    if(current_file_entry->begin<=pos && current_file_entry->end>pos){
-      fseeko(current_file_entry->f,
-	     pos-current_file_entry->begin+current_file_entry->data,
-	     SEEK_SET);
-      cursor=pos;
-      pthread_mutex_unlock(&master_mutex);
-      return 0;
-    }
-  }
-  i--;
-
-  pos=current_file_entry->end;
-  fseeko(current_file_entry->f,
-	 pos-current_file_entry->begin+current_file_entry->data,
-	 SEEK_SET);
-  cursor=pos;
-  pthread_mutex_unlock(&master_mutex);
-  return(0);
-}
-
-int aread(double **buf){
-  int read_b=0,i,j,k;
-  int toread_b=block*ch*inbytes;
-  unsigned char *readbuf;
-  double M,S;
-  
-  pthread_mutex_lock(&master_mutex);
-
-  /* the non-streaming case */
-  if(Bcursor<0 && 
-     cursor>=current_file_entry->end &&
-     current_file_entry->end!=-1){
-    pthread_mutex_unlock(&master_mutex);
-    return -1; /* EOF */
-  }
-
-  /* the streaming case */
-  if(feof(current_file_entry->f) && 
-     current_file_entry_number+1>=file_entries){
-    pthread_mutex_unlock(&master_mutex);
-    return -1;
-  }
-
-  if(primed){
-    for(j=0;j<ch;j++)
-      memmove(buf[j],buf[j]+block/2,sizeof(**buf)*block/2);
-    toread_b/=2;
-  }
-
-  readbuf=alloca(toread_b);
-
-  while(toread_b){
-    off_t ret;
-    off_t read_this_loop=current_file_entry->end-cursor;
-    if(read_this_loop>toread_b)read_this_loop=toread_b;
-
-    ret=fread(readbuf+read_b,1,read_this_loop,current_file_entry->f);
-
-    if(ret>0){
-      read_b+=ret;
-      toread_b-=ret;
-      cursor+=ret;
-    }else{
-      if(current_file_entry_number+1>=file_entries){
-	memset(readbuf+read_b,0,toread_b);
-	read_b+=toread_b;
-	toread_b=0;
-      }
-    }
-
-    if(Bcursor!=-1 && cursor>=Bcursor){
-      if(loop_flag)
-	aseek(Acursor);
-      else{
-	pthread_mutex_unlock(&master_mutex);
-	return(-1);
-      }
-    }else if(cursor>=current_file_entry->end){
-      if(current_file_entry_number+1<file_entries){
-	current_file_entry_number++;
-	current_file_entry++;
-	fseeko(current_file_entry->f,current_file_entry->data,SEEK_SET);
-      }
-    }
-  }
-  
-  k=0;
-  for(i=(primed?block/2:0);i<block;i++){
-    for(j=0;j<ch;j++){
-      int val=0;
-      switch(inbytes){
-      case 1:
-	val=(readbuf[k]<<24);
-	break;
-      case 2:
-	val=(readbuf[k]<<16)|(readbuf[k+1]<<24);
-	break;
-      case 3:
-	val=(readbuf[k]<<8)|(readbuf[k+1]<<16)|(readbuf[k+2]<<24);
-	break;
-      case 4:
-	val=(readbuf[k])|(readbuf[k+1]<<8)|(readbuf[k+2]<<16)|(readbuf[k+3]<<24);
-	break;
-      }
-      if(signp)
-	buf[j][i]=val*4.6566128730e-10;
-      else
-	buf[j][i]=(val^0x80000000UL)*4.6566128730e-10;
-
-      k+=inbytes;
-    }
-    if(ch==2){
-      M=(buf[0][i]+buf[1][i])*.5;
-      S=(buf[0][i]-buf[1][i])*.5;
-      buf[0][i]=M;
-      buf[1][i]=S;
-    }
-  }    
-  primed=1;
-  pthread_mutex_unlock(&master_mutex);
-  return 0;
-}
-
-void PutNumLE(long num,FILE *f,int bytes){
-  int i=0;
-  while(bytes--){
-    fputc((num>>(i<<3))&0xff,f);
-    i++;
-  }
-}
-
-void WriteWav(FILE *f,long channels,long rate,long bits,long duration){
-  if(ftell(f)>0)
-    if(fseek(f,0,SEEK_SET))
-      return;
-  fprintf(f,"RIFF");
-  PutNumLE(duration+44-8,f,4);
-  fprintf(f,"WAVEfmt ");
-  PutNumLE(16,f,4);
-  PutNumLE(1,f,2);
-  PutNumLE(channels,f,2);
-  PutNumLE(rate,f,4);
-  PutNumLE(rate*channels*((bits-1)/8+1),f,4);
-  PutNumLE(((bits-1)/8+1)*channels,f,2);
-  PutNumLE(bits,f,2);
-  fprintf(f,"data");
-  PutNumLE(duration,f,4);
-}
-
-int isachr(FILE *f){
-  struct stat s;
-
-  if(!fstat(fileno(f),&s))
-    if(S_ISCHR(s.st_mode)) return 1;
-  return 0;
-}
-
-/* playback must be halted to change blocksize. */
-void *playback_thread(void *dummy){
-  FILE *playback_fd=NULL;
-  int i,j,k;
-  int format=AFMT_S16_NE;
-  int channels=ch;
-  int irate=rate;
-  unsigned char *audiobuf;
-  int audiobufsize;
-  int ret,fd;
-  double **buf;
-  double **work;
-  double **save;
-  int bigendianp=0;
-  double scale;
-  int last=0;
-  off_t count=0;
-
-  pthread_mutex_lock(&master_mutex);
-  //block=wc.block_a;
-  //scale=2./block;
-  pthread_mutex_unlock(&master_mutex);
-
-  if(outfileno==-1){
-    playback_fd=fopen("/dev/dsp","wb");
-  }else{
-    playback_fd=fdopen(dup(outfileno),"wb");
-  }
-  if(!playback_fd){
-    playback_active=0;
-    playback_exit=0;
-    return NULL;
-  }
-
-  /* is this file a block device? */
-  if(isachr(playback_fd)){
-    int fragment=0x7fff0008;
-
-    fd=fileno(playback_fd);
-
-    /* try to lower the DSP delay; this ioctl may fail gracefully */
-    ret=ioctl(fd,SNDCTL_DSP_SETFRAGMENT,&fragment);
-    if(ret){
-      fprintf(stderr,"Could not set DSP fragment size; continuing.\n");
-    }
-
-    ret=ioctl(fd,SNDCTL_DSP_SETFMT,&format);
-    if(ret || format!=AFMT_S16_NE){
-      fprintf(stderr,"Could not set AFMT_S16_NE playback\n");
-      exit(1);
-    }
-    ret=ioctl(fd,SNDCTL_DSP_CHANNELS,&channels);
-    if(ret || channels!=ch){
-      fprintf(stderr,"Could not set %d channel playback\n",ch);
-      exit(1);
-    }
-    ret=ioctl(fd,SNDCTL_DSP_SPEED,&irate);
-    if(ret || irate!=rate){
-      fprintf(stderr,"Could not set %dHz playback\n",44100);
-      exit(1);
-    }
-
-    if(AFMT_S16_NE==AFMT_S16_BE)bigendianp=1;
-
-  }else{
-    WriteWav(playback_fd,ch,rate,outbytes*8,-1);
-  }
-
-  buf=alloca(sizeof(*buf)*ch);
-  work=alloca(sizeof(*work)*ch);
-  save=alloca(sizeof(*save)*ch);
-  for(i=0;i<ch;i++){
-    buf[i]=alloca(sizeof(**buf)*block);
-    work[i]=alloca(sizeof(**work)*block);
-    save[i]=alloca(sizeof(**save)*block/2);
-    memset(save[i],0,sizeof(**save)*block/2);
-  }
-  audiobufsize=block/2*ch*outbytes;
-  audiobuf=alloca(audiobufsize);
-  aseek(cursor);
-  primed=0;
-
-  while(1){
-    if(playback_exit)break;
-
-    /* get data */
-    if(aread(buf))break;
-
-
-    /* processing goes here */
-
-
-    /* Back to L/R if stereo */
-    
-    if(ch==2){
-      for(i=0;i<block;i++){
-	double L=(buf[0][i]+buf[1][i])*.5;
-	double R=(buf[0][i]-buf[1][i])*.5;
-	buf[0][i]=L;
-	buf[1][i]=R;
-      }
-    }
-
-    /* final limiting */
-
-    for(k=0,i=0;i<block/2;i++){
-      for(j=0;j<ch;j++){
-	int val=rint(buf[j][i]*32767.);
-	if(val>32767)val=32767;
-	if(val<-32768)val=-32768;
-	if(bigendianp){
-	  audiobuf[k++]=val>>8;
-	  audiobuf[k++]=val;
-	}else{
-	  audiobuf[k++]=val;
-	  audiobuf[k++]=val>>8;
-	}
-      }
-    }
-    {
-      struct timeval tv;
-      long foo;
-      gettimeofday(&tv,NULL);
-      foo=tv.tv_sec*10+tv.tv_usec/100000;
-      if(last!=foo)
-	write(eventpipe[1],"",1);
-      last=foo;
-    }
-
-    count+=fwrite(audiobuf,1,audiobufsize,playback_fd);
-
-  }
-
-  if(isachr(playback_fd)){
-    fd=fileno(playback_fd);
-    ret=ioctl(fd,SNDCTL_DSP_RESET);
-  }else{
-    WriteWav(playback_fd,ch,rate,outbytes*8,count);
-  }
-
-  fclose(playback_fd);
-  playback_active=0;
-  playback_exit=0;
-  write(eventpipe[1],"",1);
-  return(NULL);
-}
-
-int main(int argc, char **argv){
-  off_t total=0;
-  int i,j;
-  int configfd=-1;
-  int stdinp=0;
+int input_load(int n,char *list[]){
   char *fname="stdin";
+  int stdinp=0,i,j,ch,rate;
+  off_t total=0;
 
-  /* parse command line and open all the input files */
-  if(argc==1){
+  if(n==0){
     /* look at stdin... is it a file, pipe, tty...? */
     if(isatty(STDIN_FILENO)){
       fprintf(stderr,
               "Postfish requires input either as a list of contiguous WAV\n"
               "files on the command line, or WAV data piped|redirected to\n"
               "stdin.\n");
-      exit(1);
+      return 1;
     }
     stdinp=1;    /* file coming in via stdin */
     file_entries=1;
   }else
-    file_entries=argc-1;
+    file_entries=n;
 
   file_list=calloc(file_entries,sizeof(file_entry));
-  for(i=1;i<=file_entries;i++){
+  for(i=0;i<file_entries;i++){
     FILE *f;
     
     if(stdinp){
       int newfd=dup(STDIN_FILENO);
       f=fdopen(newfd,"rb");
     }else{
-      f=fopen(argv[i],"rb");
-      fname=argv[i];
+      f=fopen(list[i],"rb");
+      fname=list[i];
     }
 
     if(f){
@@ -518,7 +188,7 @@
       off_t filelength;
       int datap=0;
       int fmtp=0;
-      file_list[i-1].f=f;
+      file_list[i].f=f;
       
       /* parse header (well, sort of) and get file size */
       seekable=(fseek(f,0,SEEK_CUR)?0:1);
@@ -533,7 +203,7 @@
       fread(buffer,1,12,f);
       if(strncmp(buffer,"RIFF",4) || strncmp(buffer+8,"WAVE",4)){
         fprintf(stderr,"%s: Not a WAVE file.\n",fname);
-	exit(1);
+	return 1;
       }
 
       while(fread(buffer,1,8,f)==8){
@@ -548,7 +218,7 @@
 
           if(chunklen>80){
             fprintf(stderr,"%s: WAVE file fmt chunk too large to parse.\n",fname);
-	    exit(1);
+	    return 1;
           }
           fread(buffer,1,chunklen,f);
           
@@ -559,10 +229,10 @@
 
           if(ltype!=1){
             fprintf(stderr,"%s: WAVE file not PCM.\n",fname);
-	    exit(1);
+	    return 1;
           }
 
-	  if(i==1){
+	  if(i==0){
             ch=lch;
             rate=lrate;
             inbytes=lbits/8;
@@ -570,15 +240,15 @@
           }else{
             if(ch!=lch){
               fprintf(stderr,"%s: WAVE files must all have same number of channels.\n",fname);
-	      exit(1);
+	      return 1;
             }
             if(rate!=lrate){
               fprintf(stderr,"%s: WAVE files must all be same sampling rate.\n",fname);
-	      exit(1);
+	      return 1;
             }
             if(inbytes!=lbits/8){
               fprintf(stderr,"%s: WAVE files must all be same sample width.\n",fname);
-	      exit(1);
+	      return 1;
             }
           }
           fmtp=1;
@@ -586,7 +256,7 @@
           off_t pos=ftello(f);
           if(!fmtp){
             fprintf(stderr,"%s: WAVE fmt chunk must preceed data chunk.\n",fname);
-	    exit(1);
+	    return 1;
           }
           datap=1;
           
@@ -596,19 +266,19 @@
           if(chunklen==0UL ||
              chunklen==0x7fffffffUL || 
              chunklen==0xffffffffUL){
-	    file_list[i-1].begin=total;
-	    total=file_list[i-1].end=0;
+	    file_list[i].begin=total;
+	    total=file_list[i].end=0;
             fprintf(stderr,"%s: Incomplete header; assuming stream.\n",fname);
           }else if(filelength==-1 || chunklen+pos<=filelength){
-	    file_list[i-1].begin=total;
-	    total=file_list[i-1].end=total+chunklen;
+	    file_list[i].begin=total;
+	    total=file_list[i].end=total+chunklen;
             fprintf(stderr,"%s: Using declared file size.\n",fname);
           }else{
-	    file_list[i-1].begin=total;
-	    total=file_list[i-1].end=total+filelength-pos;
+	    file_list[i].begin=total;
+	    total=file_list[i].end=total+filelength-pos;
             fprintf(stderr,"%s: Using actual file size.\n",fname);
           }
-	  file_list[i-1].data=ftello(f);
+	  file_list[i].data=ftello(f);
           
           break;
         } else {
@@ -621,60 +291,144 @@
 
       if(!datap){
         fprintf(stderr,"%s: WAVE file has no data chunk.\n",fname);
-	exit(1);
+	return 1;
       }
       
     }else{
       fprintf(stderr,"%s: Unable to open file.\n",fname);
-      exit(1);
+      return 1;
     }
   }
 
-  /* look at stdout... do we have a file or device? */
-  if(!isatty(STDOUT_FILENO)){
-    /* apparently; assume this is the file/device for output */
-    loop_flag=0;
-    outfileno=dup(STDOUT_FILENO);
-    dup2(STDERR_FILENO,STDOUT_FILENO);
-  }
+  out.samples=4096;
+  input_ch=out.channels=ch;
+  out.rate=rate;
+  out.data=malloc(sizeof(*out.data)*ch);
+  for(i=0;i<ch;i++)
+    out.data[i]=malloc(sizeof(*out.data[0])*out.samples);
+  
+  return 0;
+}
 
+int input_seek(off_t pos){
+  int i;
 
-  /* load config */
-#if 0
-  {
-    configfd=open(".postfishrc",O_RDWR|O_CREAT,0666);
-    if(configfd>=0)load_settings(configfd);
+  if(pos<0)pos=0;
+  if(!seekable){
+    current_file_entry=file_list;
+    current_file_entry_number=0;
+    return -1;
   }
-#endif
 
-  /* set up the hack for interthread gtk event triggering through
-   input subversion */
-  if(pipe(eventpipe)){
-    fprintf(stderr,"Unable to open event pipe:\n"
-            "  %s\n",strerror(errno));
-    
-    exit(1);
+  for(i=0;i<file_entries;i++){
+    current_file_entry=file_list+i;
+    current_file_entry_number=i;
+    if(current_file_entry->begin<=pos && current_file_entry->end>pos){
+      fseeko(current_file_entry->f,
+	     pos-current_file_entry->begin+current_file_entry->data,
+	     SEEK_SET);
+      pthread_mutex_lock(&master_mutex);
+      cursor=pos;
+      pthread_mutex_unlock(&master_mutex);
+      return 0;
+    }
   }
+  i--;
 
-  aseek(0);
+  pos=current_file_entry->end;
+  fseeko(current_file_entry->f,
+	 pos-current_file_entry->begin+current_file_entry->data,
+	 SEEK_SET);
+  pthread_mutex_lock(&master_mutex);
+  cursor=pos;
+  pthread_mutex_unlock(&master_mutex);
+  return(0);
+}
 
-  mainpanel_go(argc,argv);
+time_linkage *input_read(void){
+  int read_b=0,i,j,k;
+  int toread_b=out.samples*out.channels*inbytes;
+  unsigned char *readbuf;
 
-  playback_exit=1;
+  pthread_mutex_lock(&master_mutex);
 
-  while(1){
-    if(playback_active){
-      sched_yield();
-    }else
-      break;
+  /* the non-streaming case */
+  if(!loop_active && 
+     cursor>=current_file_entry->end &&
+     current_file_entry->end!=-1){
+    pthread_mutex_unlock(&master_mutex);
+    return NULL; /* EOF */
   }
 
-  //save_settings(configfd);
-  if(configfd>=0)close(configfd);
-  return(0);
-}
+  /* the streaming case */
+  if(feof(current_file_entry->f) && 
+     current_file_entry_number+1>=file_entries){
+    pthread_mutex_unlock(&master_mutex);
+    return NULL;
+  }
+  pthread_mutex_unlock(&master_mutex);
 
+  readbuf=alloca(toread_b);
 
+  while(toread_b){
+    off_t ret;
+    off_t read_this_loop=current_file_entry->end-cursor;
+    if(read_this_loop>toread_b)read_this_loop=toread_b;
 
+    ret=fread(readbuf+read_b,1,read_this_loop,current_file_entry->f);
+
+    pthread_mutex_lock(&master_mutex);
+
+    if(ret>0){
+      read_b+=ret;
+      toread_b-=ret;
+      cursor+=ret;
+    }else{
+      if(current_file_entry_number+1>=file_entries){
+	memset(readbuf+read_b,0,toread_b);
+	read_b+=toread_b;
+	toread_b=0;
+      }
+    }
 
+    if(loop_active && cursor>=Bcursor){
+      pthread_mutex_unlock(&master_mutex);
+      input_seek(Acursor);
+    }else if(cursor>=current_file_entry->end){
+      pthread_mutex_unlock(&master_mutex);
+      if(current_file_entry_number+1<file_entries){
+	current_file_entry_number++;
+	current_file_entry++;
+	fseeko(current_file_entry->f,current_file_entry->data,SEEK_SET);
+      }
+    }
+  }
+  
+  k=0;
+  for(i=0;i<out.samples;i++){
+    for(j=0;j<out.channels;j++){
+      long val=0;
+      switch(inbytes){
+      case 1:
+	val=(readbuf[k]<<24);
+	break;
+      case 2:
+	val=(readbuf[k]<<16)|(readbuf[k+1]<<24);
+	break;
+      case 3:
+	val=(readbuf[k]<<8)|(readbuf[k+1]<<16)|(readbuf[k+2]<<24);
+	break;
+      case 4:
+	val=(readbuf[k])|(readbuf[k+1]<<8)|(readbuf[k+2]<<16)|(readbuf[k+3]<<24);
+	break;
+      }
+      if(signp)
+	out.data[j][i]=val*4.6566128730e-10;
+      else
+	out.data[j][i]=(val^0x80000000UL)*4.6566128730e-10;
 
+      k+=inbytes;
+    }
+  }    
+  return &out;
+}

<p><p>1.2       +9 -0      postfish/input.h

Index: input.h
===================================================================
RCS file: /usr/local/cvsroot/postfish/input.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- input.h	12 Oct 2003 00:46:21 -0000	1.1
+++ input.h	13 Oct 2003 06:01:22 -0000	1.2
@@ -0,0 +1,9 @@
+extern void input_Acursor_set(off_t c);
+extern void input_Bcursor_set(off_t c);
+extern off_t input_cursor_get();
+extern off_t input_time_to_cursor(char *t);
+extern void input_cursor_to_time(off_t cursor,char *t);
+extern void time_fix(char *buffer);
+extern int input_seek(off_t pos);
+extern time_linkage *input_read(void);
+extern int input_load(int n,char *list[]);

<p><p>1.5       +9 -537    postfish/main.c

Index: main.c
===================================================================
RCS file: /usr/local/cvsroot/postfish/main.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- main.c	12 Oct 2003 00:49:48 -0000	1.4
+++ main.c	13 Oct 2003 06:01:22 -0000	1.5
@@ -27,555 +27,28 @@
    on purpose. */
 
 /* sound playback code is OSS-specific for now */
-
-#define _GNU_SOURCE
-#define _LARGEFILE_SOURCE 
-#define _LARGEFILE64_SOURCE
-#define _FILE_OFFSET_BITS 64
-#define _REENTRANT 1
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <string.h>
-#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>
-#include <signal.h>
-#include <fcntl.h>
-#include <sys/soundcard.h>
-#include <sys/ioctl.h>
-
+#include "postfish.h"
 #include "mainpanel.h"
-
-static int outfileno=-1;
-sig_atomic_t loop_flag=1;
-static int inbytes=0;
-static int outbytes=2;
-static int rate=0;
-sig_atomic_t ch=0;
-static int signp=0;
-
-/* working space */
-typedef struct time_linkage {
-  int samples;
-  int channels;
-  double **data;
-} time_linkage;
-
-static off_t Acursor=0;
-static off_t Bcursor=-1;
-static long  T=-1;
-static off_t cursor=0;
+#include "input.h"
 
 pthread_mutex_t master_mutex=PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
 
-sig_atomic_t primed=0;
-sig_atomic_t playback_active=0;
-sig_atomic_t playback_exit=0;
-sig_atomic_t loop_active;
-
+int outfileno=-1;
 int eventpipe[2];
 
-typedef struct {
-  FILE *f;
-  
-  off_t begin;
-  off_t end;
-  off_t data;
-
-} file_entry;
-
-file_entry *file_list=NULL;
-int file_entries=0;
-int current_file_entry_number=-1;
-file_entry *current_file_entry=NULL;
-int seekable=0;
-
-int aseek(off_t pos){
-  int i;
-
-  if(pos<0)pos=0;
-  if(!seekable){
-    current_file_entry=file_list;
-    current_file_entry_number=0;
-    return -1;
-  }
-
-  pthread_mutex_lock(&master_mutex);
-  for(i=0;i<file_entries;i++){
-    current_file_entry=file_list+i;
-    current_file_entry_number=i;
-    if(current_file_entry->begin<=pos && current_file_entry->end>pos){
-      fseeko(current_file_entry->f,
-	     pos-current_file_entry->begin+current_file_entry->data,
-	     SEEK_SET);
-      cursor=pos;
-      pthread_mutex_unlock(&master_mutex);
-      return 0;
-    }
-  }
-  i--;
-
-  pos=current_file_entry->end;
-  fseeko(current_file_entry->f,
-	 pos-current_file_entry->begin+current_file_entry->data,
-	 SEEK_SET);
-  cursor=pos;
-  pthread_mutex_unlock(&master_mutex);
-  return(0);
-}
-
-int aread(double **buf){
-  int read_b=0,i,j,k;
-  int toread_b=block*ch*inbytes;
-  unsigned char *readbuf;
-  double M,S;
-  
-  pthread_mutex_lock(&master_mutex);
-
-  /* the non-streaming case */
-  if(Bcursor<0 && 
-     cursor>=current_file_entry->end &&
-     current_file_entry->end!=-1){
-    pthread_mutex_unlock(&master_mutex);
-    return -1; /* EOF */
-  }
-
-  /* the streaming case */
-  if(feof(current_file_entry->f) && 
-     current_file_entry_number+1>=file_entries){
-    pthread_mutex_unlock(&master_mutex);
-    return -1;
-  }
-
-  if(primed){
-    for(j=0;j<ch;j++)
-      memmove(buf[j],buf[j]+block/2,sizeof(**buf)*block/2);
-    toread_b/=2;
-  }
-
-  readbuf=alloca(toread_b);
-
-  while(toread_b){
-    off_t ret;
-    off_t read_this_loop=current_file_entry->end-cursor;
-    if(read_this_loop>toread_b)read_this_loop=toread_b;
-
-    ret=fread(readbuf+read_b,1,read_this_loop,current_file_entry->f);
-
-    if(ret>0){
-      read_b+=ret;
-      toread_b-=ret;
-      cursor+=ret;
-    }else{
-      if(current_file_entry_number+1>=file_entries){
-	memset(readbuf+read_b,0,toread_b);
-	read_b+=toread_b;
-	toread_b=0;
-      }
-    }
-
-    if(Bcursor!=-1 && cursor>=Bcursor){
-      if(loop_flag)
-	aseek(Acursor);
-      else{
-	pthread_mutex_unlock(&master_mutex);
-	return(-1);
-      }
-    }else if(cursor>=current_file_entry->end){
-      if(current_file_entry_number+1<file_entries){
-	current_file_entry_number++;
-	current_file_entry++;
-	fseeko(current_file_entry->f,current_file_entry->data,SEEK_SET);
-      }
-    }
-  }
-  
-  k=0;
-  for(i=(primed?block/2:0);i<block;i++){
-    for(j=0;j<ch;j++){
-      int val=0;
-      switch(inbytes){
-      case 1:
-	val=(readbuf[k]<<24);
-	break;
-      case 2:
-	val=(readbuf[k]<<16)|(readbuf[k+1]<<24);
-	break;
-      case 3:
-	val=(readbuf[k]<<8)|(readbuf[k+1]<<16)|(readbuf[k+2]<<24);
-	break;
-      case 4:
-	val=(readbuf[k])|(readbuf[k+1]<<8)|(readbuf[k+2]<<16)|(readbuf[k+3]<<24);
-	break;
-      }
-      if(signp)
-	buf[j][i]=val*4.6566128730e-10;
-      else
-	buf[j][i]=(val^0x80000000UL)*4.6566128730e-10;
-
-      k+=inbytes;
-    }
-    if(ch==2){
-      M=(buf[0][i]+buf[1][i])*.5;
-      S=(buf[0][i]-buf[1][i])*.5;
-      buf[0][i]=M;
-      buf[1][i]=S;
-    }
-  }    
-  primed=1;
-  pthread_mutex_unlock(&master_mutex);
-  return 0;
-}
-
-void PutNumLE(long num,FILE *f,int bytes){
-  int i=0;
-  while(bytes--){
-    fputc((num>>(i<<3))&0xff,f);
-    i++;
-  }
-}
-
-void WriteWav(FILE *f,long channels,long rate,long bits,long duration){
-  if(ftell(f)>0)
-    if(fseek(f,0,SEEK_SET))
-      return;
-  fprintf(f,"RIFF");
-  PutNumLE(duration+44-8,f,4);
-  fprintf(f,"WAVEfmt ");
-  PutNumLE(16,f,4);
-  PutNumLE(1,f,2);
-  PutNumLE(channels,f,2);
-  PutNumLE(rate,f,4);
-  PutNumLE(rate*channels*((bits-1)/8+1),f,4);
-  PutNumLE(((bits-1)/8+1)*channels,f,2);
-  PutNumLE(bits,f,2);
-  fprintf(f,"data");
-  PutNumLE(duration,f,4);
-}
-
-int isachr(FILE *f){
-  struct stat s;
-
-  if(!fstat(fileno(f),&s))
-    if(S_ISCHR(s.st_mode)) return 1;
-  return 0;
-}
-
-/* playback must be halted to change blocksize. */
-void *playback_thread(void *dummy){
-  FILE *playback_fd=NULL;
-  int i,j,k;
-  int format=AFMT_S16_NE;
-  int channels=ch;
-  int irate=rate;
-  unsigned char *audiobuf;
-  int audiobufsize;
-  int ret,fd;
-  double **buf;
-  double **work;
-  double **save;
-  int bigendianp=0;
-  double scale;
-  int last=0;
-  off_t count=0;
-
-  pthread_mutex_lock(&master_mutex);
-  //block=wc.block_a;
-  //scale=2./block;
-  pthread_mutex_unlock(&master_mutex);
-
-  if(outfileno==-1){
-    playback_fd=fopen("/dev/dsp","wb");
-  }else{
-    playback_fd=fdopen(dup(outfileno),"wb");
-  }
-  if(!playback_fd){
-    playback_active=0;
-    playback_exit=0;
-    return NULL;
-  }
-
-  /* is this file a block device? */
-  if(isachr(playback_fd)){
-    int fragment=0x7fff0008;
-
-    fd=fileno(playback_fd);
-
-    /* try to lower the DSP delay; this ioctl may fail gracefully */
-    ret=ioctl(fd,SNDCTL_DSP_SETFRAGMENT,&fragment);
-    if(ret){
-      fprintf(stderr,"Could not set DSP fragment size; continuing.\n");
-    }
-
-    ret=ioctl(fd,SNDCTL_DSP_SETFMT,&format);
-    if(ret || format!=AFMT_S16_NE){
-      fprintf(stderr,"Could not set AFMT_S16_NE playback\n");
-      exit(1);
-    }
-    ret=ioctl(fd,SNDCTL_DSP_CHANNELS,&channels);
-    if(ret || channels!=ch){
-      fprintf(stderr,"Could not set %d channel playback\n",ch);
-      exit(1);
-    }
-    ret=ioctl(fd,SNDCTL_DSP_SPEED,&irate);
-    if(ret || irate!=rate){
-      fprintf(stderr,"Could not set %dHz playback\n",44100);
-      exit(1);
-    }
-
-    if(AFMT_S16_NE==AFMT_S16_BE)bigendianp=1;
-
-  }else{
-    WriteWav(playback_fd,ch,rate,outbytes*8,-1);
-  }
-
-  buf=alloca(sizeof(*buf)*ch);
-  work=alloca(sizeof(*work)*ch);
-  save=alloca(sizeof(*save)*ch);
-  for(i=0;i<ch;i++){
-    buf[i]=alloca(sizeof(**buf)*block);
-    work[i]=alloca(sizeof(**work)*block);
-    save[i]=alloca(sizeof(**save)*block/2);
-    memset(save[i],0,sizeof(**save)*block/2);
-  }
-  audiobufsize=block/2*ch*outbytes;
-  audiobuf=alloca(audiobufsize);
-  aseek(cursor);
-  primed=0;
-
-  while(1){
-    if(playback_exit)break;
-
-    /* get data */
-    if(aread(buf))break;
-
-
-    /* processing goes here */
-
-
-    /* Back to L/R if stereo */
-    
-    if(ch==2){
-      for(i=0;i<block;i++){
-	double L=(buf[0][i]+buf[1][i])*.5;
-	double R=(buf[0][i]-buf[1][i])*.5;
-	buf[0][i]=L;
-	buf[1][i]=R;
-      }
-    }
-
-    /* final limiting */
-
-    for(k=0,i=0;i<block/2;i++){
-      for(j=0;j<ch;j++){
-	int val=rint(buf[j][i]*32767.);
-	if(val>32767)val=32767;
-	if(val<-32768)val=-32768;
-	if(bigendianp){
-	  audiobuf[k++]=val>>8;
-	  audiobuf[k++]=val;
-	}else{
-	  audiobuf[k++]=val;
-	  audiobuf[k++]=val>>8;
-	}
-      }
-    }
-    {
-      struct timeval tv;
-      long foo;
-      gettimeofday(&tv,NULL);
-      foo=tv.tv_sec*10+tv.tv_usec/100000;
-      if(last!=foo)
-	write(eventpipe[1],"",1);
-      last=foo;
-    }
-
-    count+=fwrite(audiobuf,1,audiobufsize,playback_fd);
-
-  }
-
-  if(isachr(playback_fd)){
-    fd=fileno(playback_fd);
-    ret=ioctl(fd,SNDCTL_DSP_RESET);
-  }else{
-    WriteWav(playback_fd,ch,rate,outbytes*8,count);
-  }
-
-  fclose(playback_fd);
-  playback_active=0;
-  playback_exit=0;
-  write(eventpipe[1],"",1);
-  return(NULL);
-}
-
 int main(int argc, char **argv){
-  off_t total=0;
-  int i,j;
   int configfd=-1;
-  int stdinp=0;
-  char *fname="stdin";
 
   /* parse command line and open all the input files */
-  if(argc==1){
-    /* look at stdin... is it a file, pipe, tty...? */
-    if(isatty(STDIN_FILENO)){
-      fprintf(stderr,
-	      "Postfish requires input either as a list of contiguous WAV\n"
-	      "files on the command line, or WAV data piped|redirected to\n"
-	      "stdin.\n");
-      exit(1);
-    }
-    stdinp=1;    /* file coming in via stdin */
-    file_entries=1;
-  }else
-    file_entries=argc-1;
-
-  file_list=calloc(file_entries,sizeof(file_entry));
-  for(i=1;i<=file_entries;i++){
-    FILE *f;
-    
-    if(stdinp){
-      int newfd=dup(STDIN_FILENO);
-      f=fdopen(newfd,"rb");
-    }else{
-      f=fopen(argv[i],"rb");
-      fname=argv[i];
-    }
-
-    if(f){
-      unsigned char buffer[81];
-      off_t filelength;
-      int datap=0;
-      int fmtp=0;
-      file_list[i-1].f=f;
-      
-      /* parse header (well, sort of) and get file size */
-      seekable=(fseek(f,0,SEEK_CUR)?0:1);
-      if(!seekable){
-	filelength=-1;
-      }else{
-	fseek(f,0,SEEK_END);
-	filelength=ftello(f);
-	fseek(f,0,SEEK_SET);
-      }
-
-      fread(buffer,1,12,f);
-      if(strncmp(buffer,"RIFF",4) || strncmp(buffer+8,"WAVE",4)){
-	fprintf(stderr,"%s: Not a WAVE file.\n",fname);
-	exit(1);
-      }
-
-      while(fread(buffer,1,8,f)==8){
-	unsigned long chunklen=
-	  buffer[4]|(buffer[5]<<8)|(buffer[6]<<16)|(buffer[7]<<24);
-
-	if(!strncmp(buffer,"fmt ",4)){
-	  int ltype;
-	  int lch;
-	  int lrate;
-	  int lbits;
-
-	  if(chunklen>80){
-	    fprintf(stderr,"%s: WAVE file fmt chunk too large to parse.\n",fname);
-	    exit(1);
-	  }
-	  fread(buffer,1,chunklen,f);
-	  
-	  ltype=buffer[0] |(buffer[1]<<8);
-	  lch=  buffer[2] |(buffer[3]<<8);
-	  lrate=buffer[4] |(buffer[5]<<8)|(buffer[6]<<16)|(buffer[7]<<24);
-	  lbits=buffer[14]|(buffer[15]<<8);
-
-	  if(ltype!=1){
-	    fprintf(stderr,"%s: WAVE file not PCM.\n",fname);
-	    exit(1);
-	  }
-
-	  if(i==1){
-	    ch=lch;
-	    rate=lrate;
-	    inbytes=lbits/8;
-	    if(inbytes>1)signp=1;
-	  }else{
-	    if(ch!=lch){
-	      fprintf(stderr,"%s: WAVE files must all have same number of channels.\n",fname);
-	      exit(1);
-	    }
-	    if(rate!=lrate){
-	      fprintf(stderr,"%s: WAVE files must all be same sampling rate.\n",fname);
-	      exit(1);
-	    }
-	    if(inbytes!=lbits/8){
-	      fprintf(stderr,"%s: WAVE files must all be same sample width.\n",fname);
-	      exit(1);
-	    }
-	  }
-	  fmtp=1;
-	} else if(!strncmp(buffer,"data",4)){
-	  off_t pos=ftello(f);
-	  if(!fmtp){
-	    fprintf(stderr,"%s: WAVE fmt chunk must preceed data chunk.\n",fname);
-	    exit(1);
-	  }
-	  datap=1;
-	  
-	  if(seekable)
-	    filelength=(filelength-pos)/(ch*inbytes)*(ch*inbytes)+pos;
-
-	  if(chunklen==0UL ||
-	     chunklen==0x7fffffffUL || 
-	     chunklen==0xffffffffUL){
-	    file_list[i-1].begin=total;
-	    total=file_list[i-1].end=0;
-	    fprintf(stderr,"%s: Incomplete header; assuming stream.\n",fname);
-	  }else if(filelength==-1 || chunklen+pos<=filelength){
-	    file_list[i-1].begin=total;
-	    total=file_list[i-1].end=total+chunklen;
-	    fprintf(stderr,"%s: Using declared file size.\n",fname);
-	  }else{
-	    file_list[i-1].begin=total;
-	    total=file_list[i-1].end=total+filelength-pos;
-	    fprintf(stderr,"%s: Using actual file size.\n",fname);
-	  }
-	  file_list[i-1].data=ftello(f);
-	  
-	  break;
-	} else {
-	  fprintf(stderr,"%s: Unknown chunk type %c%c%c%c; skipping.\n",fname,
-		  buffer[0],buffer[1],buffer[2],buffer[3]);
-	  for(j=0;j<(int)chunklen;j++)
-	    if(fgetc(f)==EOF)break;
-	}
-      }
-
-      if(!datap){
-	fprintf(stderr,"%s: WAVE file has no data chunk.\n",fname);
-	exit(1);
-      }
-      
-    }else{
-      fprintf(stderr,"%s: Unable to open file.\n",fname);
-      exit(1);
-    }
-  }
+  if(input_load(argc-1,argv+1))exit(1);
 
   /* look at stdout... do we have a file or device? */
   if(!isatty(STDOUT_FILENO)){
-    /* apparently; assume this is the file/device for output */
-    loop_flag=0;
+    /* assume this is the file/device for output */
     outfileno=dup(STDOUT_FILENO);
     dup2(STDERR_FILENO,STDOUT_FILENO);
   }
 
-
   /* load config */
 #if 0
   {
@@ -584,8 +57,8 @@
   }
 #endif
 
-  /* set up the hack for interthread gtk event triggering through
-   input subversion */
+  /* easiest way to inform gtk of changes and not deal with locking
+     issues around the UI */
   if(pipe(eventpipe)){
     fprintf(stderr,"Unable to open event pipe:\n"
             "  %s\n",strerror(errno));
@@ -593,9 +66,8 @@
     exit(1);
   }
 
-  aseek(0);
-
-  mainpanel_go(argc,argv);
+  input_seek(0);
+  mainpanel_go(argc,argv,input_ch);
 
   playback_exit=1;
 

<p><p>1.8       +53 -34    postfish/mainpanel.c

Index: mainpanel.c
===================================================================
RCS file: /usr/local/cvsroot/postfish/mainpanel.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- mainpanel.c	12 Oct 2003 00:42:35 -0000	1.7
+++ mainpanel.c	13 Oct 2003 06:01:22 -0000	1.8
@@ -4,11 +4,13 @@
 #include <signal.h>
 #include <stdio.h>
 #include <pthread.h>
+#include "postfish.h"
 #include "fisharray.h"
 #include "buttonicons.h"
 #include "multibar.h"
 #include "readout.h"
 #include "version.h"
+#include "input.h"
 
 typedef struct {
   GtkWidget *topframe;
@@ -54,23 +56,26 @@
 
 extern sig_atomic_t playback_active;
 extern sig_atomic_t playback_exit;
-extern sig_atomic_t ch;
 extern void *playback_thread(void *dummy);
 
 static void action_play(GtkWidget *dummy,postfish_mainpanel *p){
-  if(!playback_active){
-    pthread_t playback_thread_id;
-    playback_active=1;
-    animate_fish(p);
-    pthread_create(&playback_thread_id,NULL,&playback_thread,NULL);
+  if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))){
+    if(!playback_active){
+      pthread_t playback_thread_id;
+      playback_active=1;
+      animate_fish(p);
+      pthread_create(&playback_thread_id,NULL,&playback_thread,NULL);
+    }
   }else{
-    playback_exit=1;
-    sched_yield();
-    while(1){
-      if(playback_active){
-	sched_yield();
-      }else
-	break;
+    if(playback_active){
+      playback_exit=1;
+      sched_yield();
+      while(1){
+	if(playback_active){
+	  sched_yield();
+	}else
+	  break;
+      }
     }
   }
 }
@@ -191,7 +196,7 @@
       if(pos>13)pos=13;
       buffer[pos]=event->keyval;
 
-      timeentry_fix(buffer);
+      time_fix(buffer);
 
       pos++;
       if(pos==4 || pos==7 || pos==10)pos++;
@@ -684,12 +689,13 @@
 }
 
 #include <stdlib.h>
-void mainpanel_go(int argc,char *argv[]){
+void mainpanel_go(int argc,char *argv[], int ch){
   postfish_mainpanel p;
   char *homedir=getenv("HOME");
-  char *labels[9];
-  char *labels_gen[]={"_0","_1","_2","_3","_4","_5","_6","_7",0};
-  char *labels_st[]={"_0 left","_1 right","_2 mid","_3 side",0};
+  char *labels[11];
+  char  buffer[20];
+  int i;
+
   memset(&p,0,sizeof(p));
   gtk_rc_add_default_file("/etc/postfish/postfishrc");
   if(homedir){
@@ -701,11 +707,35 @@
   }
   gtk_init (&argc, &argv);
 
-  if(ch==2){
-    memcpy(labels,labels_st,sizeof(labels_st));
-  }else{
-    memcpy(labels,labels_gen,sizeof(labels_gen));
-    labels[ch]=0;
+  memset(labels,0,sizeof(labels));
+  switch(ch){
+  case 1:
+    labels[0]="_0 mono";
+    break;
+  case 2:
+    labels[0]="_0 left";
+    labels[1]="_1 right";
+    labels[2]="_2 mid";
+    labels[3]="_3 side";
+    break;
+  case 3:
+  case 4:
+  case 5:
+  case 6:
+  case 7:
+  case 8:
+    for(i=0;i<ch;i++){
+      sprintf(buffer,"_%d",i);
+      labels[i]=strdup(buffer);
+    }
+    sprintf(buffer,"_%d mean",i);
+    labels[i++]=strdup(buffer);
+    sprintf(buffer,"_%d diff",i);
+    labels[i++]=strdup(buffer);
+  default:
+    fprintf(stderr,"\nPostfish currently supports inputs of one to eight\n"
+	    "channels (current input request: %d channels)\n\n",ch);
+    exit(1);
   }
 
   mainpanel_create(&p,labels);
@@ -718,14 +748,3 @@
 
 
 
-
-
-
-
-
-
-
-
-
-
-

<p><p>1.2       +1 -1      postfish/mainpanel.h

Index: mainpanel.h
===================================================================
RCS file: /usr/local/cvsroot/postfish/mainpanel.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- mainpanel.h	12 Oct 2003 00:44:15 -0000	1.1
+++ mainpanel.h	13 Oct 2003 06:01:22 -0000	1.2
@@ -1 +1 @@
-extern void mainpanel_go(int argc,char *argv[]);
+extern void mainpanel_go(int n,char *list[],int ch);

<p><p>1.2       +9 -0      postfish/postfish.h

Index: postfish.h
===================================================================
RCS file: /usr/local/cvsroot/postfish/postfish.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- postfish.h	12 Oct 2003 00:46:21 -0000	1.1
+++ postfish.h	13 Oct 2003 06:01:22 -0000	1.2
@@ -56,3 +56,12 @@
 } time_linkage;
 
 extern pthread_mutex_t master_mutex;
+
+extern sig_atomic_t loop_active;
+extern sig_atomic_t playback_active;
+extern sig_atomic_t playback_exit;
+extern int outfileno;
+extern int seekable;
+extern int eventpipe[2];
+extern int input_ch;
+

<p><p>1.2       +1 -0      postfish/readout.h

Index: readout.h
===================================================================
RCS file: /usr/local/cvsroot/postfish/readout.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- readout.h	12 Oct 2003 00:44:15 -0000	1.1
+++ readout.h	13 Oct 2003 06:01:22 -0000	1.2
@@ -9,6 +9,7 @@
 #include <gtk/gtkframe.h>
 #include <gtk/gtknotebook.h>
 #include <gtk/gtklabel.h>
+#include <gtk/gtkeventbox.h>
 
 G_BEGIN_DECLS
 

<p><p>1.1                  postfish/output.c

Index: output.c
===================================================================
/*
 *
 *  postfish
 *    
 *      Copyright (C) 2002-2003 Monty
 *
 *  Postfish 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, or (at your option)
 *  any later version.
 *   
 *  Postfish 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 Postfish; see the file COPYING.  If not, write to the
 *  Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * 
 */

/* sound playback code is OSS-specific for now */
#include <linux/soundcard.h>
#include <sys/ioctl.h>
#include "postfish.h"
#include "input.h"

ig_atomic_t playback_active=0;
sig_atomic_t playback_exit=0;

tatic void PutNumLE(long num,FILE *f,int bytes){
  int i=0;
  while(bytes--){
    fputc((num>>(i<<3))&0xff,f);
    i++;
  }
}

tatic void WriteWav(FILE *f,long channels,long rate,long bits,long duration){
  if(ftell(f)>0)
    if(fseek(f,0,SEEK_SET))
      return;
  fprintf(f,"RIFF");
  PutNumLE(duration+44-8,f,4);
  fprintf(f,"WAVEfmt ");
  PutNumLE(16,f,4);
  PutNumLE(1,f,2);
  PutNumLE(channels,f,2);
  PutNumLE(rate,f,4);
  PutNumLE(rate*channels*((bits-1)/8+1),f,4);
  PutNumLE(((bits-1)/8+1)*channels,f,2);
  PutNumLE(bits,f,2);
  fprintf(f,"data");
  PutNumLE(duration,f,4);
}

tatic int isachr(FILE *f){
  struct stat s;

  if(!fstat(fileno(f),&s))
    if(S_ISCHR(s.st_mode)) return 1;
  return 0;
}

tatic FILE *playback_startup(int outfileno, int ch, int r){
  FILE *playback_fd=NULL;
  int format=AFMT_S16_NE;
  int rate=r,channels=ch,ret;

  if(outfileno==-1){
    playback_fd=fopen("/dev/dsp","wb");
  }else{
    playback_fd=fdopen(dup(outfileno),"wb");
  }

  if(!playback_fd){
    fprintf(stderr,"Unable to open output for playback\n");
    return NULL;
  }

  /* is this file a block device? */
  if(isachr(playback_fd)){
    int fragment=0x7fff000d;
    int fd=fileno(playback_fd);

    /* try to lower the DSP delay; this ioctl may fail gracefully */
    ret=ioctl(fd,SNDCTL_DSP_SETFRAGMENT,&fragment);
    if(ret){
      fprintf(stderr,"Could not set DSP fragment size; continuing.\n");
    }

    ret=ioctl(fd,SNDCTL_DSP_SETFMT,&format);
    if(ret || format!=AFMT_S16_NE){
      fprintf(stderr,"Could not set AFMT_S16_NE playback\n");
      exit(1);
    }
    ret=ioctl(fd,SNDCTL_DSP_CHANNELS,&channels);
    if(ret || channels!=ch){
      fprintf(stderr,"Could not set %d channel playback\n",ch);
      exit(1);
    }
    ret=ioctl(fd,SNDCTL_DSP_SPEED,&rate);
    if(ret || r!=rate){
      fprintf(stderr,"Could not set %dHz playback\n",r);
      exit(1);
    }
  }else{
    WriteWav(playback_fd,ch,r,16,-1);
  }

  return playback_fd;
}

/* playback must be halted to change blocksize. */
void *playback_thread(void *dummy){
  int audiobufsize=8192,i,j,k;
  unsigned char *audiobuf=malloc(audiobufsize);
  int bigendianp=(AFMT_S16_NE==AFMT_S16_BE?1:0);
  FILE *playback_fd=NULL;
  int setupp=0;
  time_linkage *ret;
  off_t count=0;
  long last=-1;

  int ch=-1;
  long rate=-1;

  while(1){
    if(playback_exit)break;

    /* get data */
    if(!(ret=input_read()))break;

    /************/

<p><p><p>    /************/

    if(ret && ret->samples>0){
      ch=ret->channels;
      rate=ret->rate;

      /* lazy playbak setup; we couldn't do it until we had rate and
         channel information from the pipeline */
      if(!setupp){
        playback_fd=playback_startup(outfileno,ch,rate);
        if(!playback_fd){
          playback_active=0;
          playback_exit=0;
          return NULL;
        }
        setupp=1;
      }

      if(audiobufsize<ret->channels*ret->samples*2){
        audiobufsize=ret->channels*ret->samples*2;
        audiobuf=realloc(audiobuf,sizeof(*audiobuf)*audiobufsize);
      }
      
      /* final limiting and conversion */
      
      for(k=0,i=0;i<ret->samples;i++){
        for(j=0;j<ret->channels;j++){
          int val=rint(ret->data[j][i]*32767.);
          if(val>32767)val=32767;
          if(val<-32768)val=-32768;
          if(bigendianp){
            audiobuf[k++]=val>>8;
            audiobuf[k++]=val;
          }else{
            audiobuf[k++]=val;
            audiobuf[k++]=val>>8;
          }
        }
      }
      {
        struct timeval tv;
        long foo;
        gettimeofday(&tv,NULL);
        foo=tv.tv_sec*10+tv.tv_usec/100000;
        if(last!=foo)
          write(eventpipe[1],"",1);
        last=foo;
      }
      
      count+=fwrite(audiobuf,1,audiobufsize,playback_fd);
    }
  }

  if(isachr(playback_fd)){
    int fd=fileno(playback_fd);
    ioctl(fd,SNDCTL_DSP_RESET);
  }else{
    if(ch>-1)
      WriteWav(playback_fd,ch,rate,16,count);
  }
  
  fclose(playback_fd);
  playback_active=0;
  playback_exit=0;
  if(audiobuf)free(audiobuf);
  write(eventpipe[1],"",1);
  return(NULL);
}

<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