libsent/src/adin/adin-cut.c

Go to the documentation of this file.
00001 
00110 /*
00111  * Copyright (c) 1991-2006 Kawahara Lab., Kyoto University
00112  * Copyright (c) 2000-2005 Shikano Lab., Nara Institute of Science and Technology
00113  * Copyright (c) 2005-2006 Julius project team, Nagoya Institute of Technology
00114  * All rights reserved
00115  */
00116 
00117 #include <sent/stddefs.h>
00118 #include <sent/speech.h>
00119 #include <sent/adin.h>
00120 #ifdef HAVE_PTHREAD
00121 #include <pthread.h>
00122 #endif
00123 
00125 #undef THREAD_DEBUG
00127 #define TMP_FIX_200602          
00128 
00134 static int c_length  = 5000;    
00135 static int c_offset  = 0;       
00136 static int wstep   = DEFAULT_WSTEP;     
00137 static int thres;               
00138 static int noise_zerocross;     
00139 static int nc_max;              
00140 
00141 
00147 static SP16 *swapbuf;           
00148 static int sbsize, sblen;       
00149 static int rest_tail;           
00150 
00151 
00157 static boolean (*ad_resume)();  
00158 static boolean (*ad_pause)();   
00159 static int (*ad_read)(SP16 *, int); 
00160 static boolean adin_cut_on;     
00161 static boolean silence_cut_default; 
00162 static boolean strip_flag;      
00163 static boolean enable_thread = FALSE;   
00164 static boolean ignore_speech_while_recog = TRUE; 
00165 static boolean need_zmean;      
00166 
00167 
00168 #ifdef HAVE_PTHREAD
00169 static void adin_thread_create(); 
00170 #endif
00171 
00178 void
00179 adin_setup_func(int (*cad_read)(SP16 *, int), 
00180                 boolean (*cad_pause)(), 
00181                 boolean (*cad_resume)(), 
00182                 boolean use_cut_def, 
00183                 boolean need_thread 
00184                 )
00185 {
00186   ad_read = cad_read;
00187   ad_pause = cad_pause;
00188   ad_resume = cad_resume;
00189   silence_cut_default = use_cut_def;
00190 #ifdef HAVE_PTHREAD
00191   enable_thread = need_thread;
00192 #else
00193   if (need_thread == TRUE) {
00194     j_printerr("Warning: thread not supported, input may be corrupted on slow machines\n");
00195   }
00196 #endif
00197 }
00198 
00215 void
00216 adin_setup_param(int silence_cut, boolean strip_zero, int cthres, int czc, int head_margin, int tail_margin, int sample_freq, boolean ignore_speech, boolean need_zeromean)
00217 {
00218   float samples_in_msec;
00219   if (silence_cut < 2) {
00220     adin_cut_on = (silence_cut == 1) ? TRUE : FALSE;
00221   } else {
00222     adin_cut_on = silence_cut_default;
00223   }
00224   strip_flag = strip_zero;
00225   thres = cthres;
00226   ignore_speech_while_recog = ignore_speech;
00227   need_zmean = need_zeromean;
00228   /* calc & set internal parameter from configuration */
00229   samples_in_msec = (float) sample_freq / (float)1000.0;
00230   /* cycle buffer length = head margin length */
00231   c_length = (int)((float)head_margin * samples_in_msec);       /* in msec. */
00232   /* compute zerocross trigger count threshold in the cycle buffer */
00233   noise_zerocross = czc * c_length / sample_freq;
00234   /* process step */
00235   wstep = DEFAULT_WSTEP;
00236   /* variables that comes from the tail margin length (in wstep) */
00237   nc_max = (int)((float)(tail_margin * samples_in_msec / (float)wstep)) + 2;
00238   sbsize = tail_margin * samples_in_msec + (c_length * czc / 200);
00239 
00240 #ifdef HAVE_PTHREAD
00241   if (enable_thread) {
00242     /* create A/D-in thread here */
00243     adin_thread_create();
00244   }
00245 #endif
00246 }
00247 
00253 boolean
00254 query_segment_on()
00255 {
00256   return adin_cut_on;
00257 }
00258 
00264 boolean
00265 query_thread_on()
00266 {
00267   return enable_thread;
00268 }
00269 
00274 void
00275 adin_reset_zmean()
00276 {
00277   if (need_zmean) zmean_reset();
00278 }
00279 
00280 
00281 #ifdef HAVE_PTHREAD
00282 
00287 static pthread_t adin_thread;   
00288 static pthread_mutex_t mutex;   
00289 static SP16 *speech;            
00290 static int speechlen;           
00291 
00300 static boolean transfer_online = FALSE; 
00301 static boolean adinthread_buffer_overflowed = FALSE; 
00302 
00303 #endif
00304 
00310 static SP16 *buffer = NULL;     
00311 static int bpmax;               
00312 static int bp;                  
00313 static int current_len;         
00314 static SP16 *cbuf;              
00315 
00316 
00317 
00323 static void
00324 adin_purge(int from)
00325 {
00326   if (from > 0 && current_len-from > 0) {
00327     memmove(buffer, &(buffer[from]), (current_len - from) * sizeof(SP16));
00328   }
00329   bp = current_len - from;
00330 }
00331 
00350 static int
00351 adin_cut(
00352          int (*ad_process)(SP16 *, int), 
00353          int (*ad_check)())     
00354 {
00355   static int i;
00356   static boolean is_valid_data; 
00357   int ad_process_ret;
00358   int imax, len, cnt;
00359   static boolean end_of_stream; /* will be set to TRUE if current input stream has reached the end (in case of file input or adinnet input).  If TRUE, no more input will be got by ad_read, but just process the already stored samples until it becomes empty */
00360   static int need_init = TRUE;  /* if TRUE, initialize buffer on startup */
00361   static int end_status;        /* return value */
00362   static boolean transfer_online_local; /* local repository of transfer_online */
00363   
00364   static int zc;                /* count of zero cross */
00365   static int nc;                /* count of current tail silence segments */
00366 
00367   /*
00368    * there are 3 buffers:
00369    *   temporary storage queue: buffer[]
00370    *   cycle buffer for zero-cross counting: (in zc_e)
00371    *   swap buffer for re-starting after short tail silence
00372    *
00373    * Each samples are first read to buffer[], then passed to count_zc_e()
00374    * to find trigger.  Samples between trigger and end of speech are 
00375    * passed to (*ad_process) with pointer to the first sample and its length.
00376    *
00377    */
00378 
00379   /**********************/
00380   /* initialize buffers */
00381   /**********************/
00382   if (buffer == NULL) {         /* beginning of stream */
00383     buffer = (SP16 *)mymalloc(sizeof(SP16) * MAXSPEECHLEN);
00384     cbuf = (SP16 *)mymalloc(sizeof(SP16) * c_length);
00385     swapbuf = (SP16 *)mymalloc(sizeof(SP16) * sbsize);
00386   }
00387   if (need_init) {
00388     bpmax = MAXSPEECHLEN;
00389     bp = 0;
00390     is_valid_data = FALSE;
00391     /* reset zero-cross status */
00392     if (adin_cut_on) {
00393       init_count_zc_e(thres, c_length, c_offset);
00394     }
00395     end_of_stream = FALSE;
00396     nc = 0;
00397     sblen = 0;
00398     need_init = FALSE;          /* for next call */
00399   }
00400       
00401   /****************/
00402   /* resume input */
00403   /****************/
00404   /* restart speech input if paused on the last call */
00405   if (ad_resume != NULL) {
00406     if ((*ad_resume)() == FALSE)  return(-1);
00407   }
00408 
00409   /*************/
00410   /* main loop */
00411   /*************/
00412   for (;;) {
00413 
00414     /****************************/
00415     /* read in new speech input */
00416     /****************************/
00417     if (end_of_stream) {
00418       /* already reaches end of stream, just process the rest */
00419       current_len = bp;
00420     } else {
00421       /*****************************************************/
00422       /* get samples from input device to temporary buffer */
00423       /*****************************************************/
00424       /* buffer[0..bp] is the current remaining samples */
00425       /*
00426         mic input - samples exist in a device buffer
00427         tcpip input - samples exist in a socket
00428         file input - samples in a file
00429            
00430         Return value is the number of read samples.
00431         If no data exists in the device (in case of mic input), ad_read()
00432         will return 0.  If reached end of stream (in case end of file or
00433         receive end ack from tcpip client), it will return -1.
00434         If error, returns -2.
00435       */
00436       cnt = (*ad_read)(&(buffer[bp]), bpmax - bp);
00437       if (cnt < 0) {            /* end of stream or error */
00438         /* set the end status */
00439         if (cnt == -2) end_status = -1; /* end by error */
00440         else if (cnt == -1) end_status = 0; /* end by normal end of stream */
00441         /* now the input has been ended, 
00442            we should not get further speech input in the next loop, 
00443            instead just process the samples in the temporary buffer until
00444            the entire data is processed. */
00445         end_of_stream = TRUE;           
00446         cnt = 0;                        /* no new input */
00447         /* in case the first trial of ad_read() fails, exit this loop */
00448         if (bp == 0) break;
00449       }
00450 
00451       /*************************************************/
00452       /* some speech processing for the incoming input */
00453       /*************************************************/
00454       if (cnt > 0) {
00455         if (strip_flag) {
00456           /* strip off successive zero samples */
00457           len = strip_zero(&(buffer[bp]), cnt);
00458           if (len != cnt) cnt = len;
00459         }
00460         if (need_zmean) {
00461           /* remove DC offset */
00462           sub_zmean(&(buffer[bp]), cnt);
00463         }
00464       }
00465       
00466       /* current len = current samples in buffer */
00467       current_len = bp + cnt;
00468     }
00469 #ifdef THREAD_DEBUG
00470     if (end_of_stream) {
00471       printf("stream already ended\n");
00472     }
00473     printf("input: get %d samples [%d-%d]\n", current_len - bp, bp, current_len);
00474 #endif
00475 
00476     /**************************************************/
00477     /* call the periodic callback (non threaded mode) */
00478     /*************************************************/
00479     /* this function is mainly for periodic checking of incoming command
00480        in module mode */
00481     /* in threaded mode, this will be done in process thread, not here in adin thread */
00482     if (ad_check != NULL
00483 #ifdef HAVE_PTHREAD
00484         && !enable_thread
00485 #endif
00486         ) {
00487       /* if ad_check() returns value < 0, termination of speech input is required */
00488       if ((i = (*ad_check)()) < 0) { /* -1: soft termination -2: hard termination */
00489         //      if ((i == -1 && current_len == 0) || i == -2) {
00490         if (i == -2 ||
00491             (i == -1 && adin_cut_on && is_valid_data == FALSE) ||
00492             (i == -1 && !adin_cut_on && current_len == 0)) {
00493           end_status = -2;      /* recognition terminated by outer function */
00494           goto break_input;
00495         }
00496       }
00497     }
00498 
00499     /***********************************************************************/
00500     /* if no data has got but not end of stream, repeat next input samples */
00501     /***********************************************************************/
00502     if (current_len == 0) continue;
00503 
00504     /* When not adin_cut mode, all incoming data is valid.
00505        So is_valid_data should be set to TRUE when some input first comes
00506        till this input ends.  So, if some data comes, set is_valid_data to
00507        TRUE here. */ 
00508     if (!adin_cut_on && is_valid_data == FALSE && current_len > 0) {
00509       is_valid_data = TRUE;
00510     }
00511 
00512     /******************************************************/
00513     /* prepare for processing samples in temporary buffer */
00514     /******************************************************/
00515     
00516     wstep = DEFAULT_WSTEP;      /* process unit (should be smaller than cycle buffer) */
00517 
00518     /* imax: total length that should be processed at one ad_read() call */
00519     /* if in real-time mode and not threaded, recognition process 
00520        will be called and executed as the ad_process() callback within
00521        this function.  If the recognition speed is over the real time,
00522        processing all the input samples at the loop below may result in the
00523        significant delay of getting next input, that may result in the buffer
00524        overflow of the device (namely a microphone device will suffer from
00525        this). So, in non-threaded mode, in order to avoid buffer overflow and
00526        input frame dropping, we will leave here by processing 
00527        only one segment [0..wstep], and leave the rest in the temporary buffer.
00528     */
00529 #ifdef HAVE_PTHREAD
00530     if (enable_thread) imax = current_len; /* process whole */
00531     else imax = (current_len < wstep) ? current_len : wstep; /* one step */
00532 #else
00533     imax = (current_len < wstep) ? current_len : wstep; /* one step */
00534 #endif
00535     
00536     /* wstep: unit length for the loop below */
00537     if (wstep > current_len) wstep = current_len;
00538 
00539 #ifdef THREAD_DEBUG
00540     printf("process %d samples by %d step\n", imax, wstep);
00541 #endif
00542 
00543 #ifdef HAVE_PTHREAD
00544     if (enable_thread) {
00545       /* get transfer status to local */
00546       pthread_mutex_lock(&mutex);
00547       transfer_online_local = transfer_online;
00548       pthread_mutex_unlock(&mutex);
00549     }
00550 #endif
00551 
00552     /*********************************************************/
00553     /* start processing buffer[0..current_len] by wstep step */
00554     /*********************************************************/
00555     i = 0;
00556     while (i + wstep <= imax) {
00557       
00558       if (adin_cut_on) {
00559 
00560         /********************/
00561         /* check triggering */
00562         /********************/
00563         /* the cycle buffer in count_zc_e() holds the last
00564            samples of (head_margin) miliseconds, and the zerocross
00565            over the threshold level are counted within the cycle buffer */
00566         
00567         /* store the new data to cycle buffer and update the count */
00568         /* return zero-cross num in the cycle buffer */
00569         zc = count_zc_e(&(buffer[i]), wstep);
00570         
00571         if (zc > noise_zerocross) { /* now triggering */
00572           
00573           if (is_valid_data == FALSE) {
00574             /*****************************************************/
00575             /* process off, trigger on: detect speech triggering */
00576             /*****************************************************/
00577             
00578             is_valid_data = TRUE;   /* start processing */
00579             nc = 0;
00580 #ifdef THREAD_DEBUG
00581             printf("detect on\n");
00582 #endif
00583             /****************************************/
00584             /* flush samples stored in cycle buffer */
00585             /****************************************/
00586             /* (last (head_margin) msec samples */
00587             /* if threaded mode, processing means storing them to speech[].
00588                if ignore_speech_while_recog is on (default), ignore the data
00589                if transfer is offline (=while processing second pass).
00590                Else, datas are stored even if transfer is offline */
00591             if ( ad_process != NULL
00592 #ifdef HAVE_PTHREAD
00593                  && (!enable_thread || !ignore_speech_while_recog || transfer_online_local)
00594 #endif
00595                  ) {
00596               /* copy content of cycle buffer to cbuf */
00597               zc_copy_buffer(cbuf, &len);
00598               /* Note that the last 'wstep' samples are the same as
00599                  the current samples 'buffer[i..i+wstep]', and
00600                  they will be processed later.  So, here only the samples
00601                  cbuf[0...len-wstep] will be processed
00602               */
00603               if (len - wstep > 0) {
00604 #ifdef THREAD_DEBUG
00605                 printf("callback for buffered samples (%d bytes)\n", len - wstep);
00606 #endif
00607                 ad_process_ret = (*ad_process)(cbuf, len - wstep);
00608                 switch(ad_process_ret) {
00609                 case 1:         /* segmentation notification from process callback */
00610 #ifdef HAVE_PTHREAD
00611                   if (enable_thread) {
00612                     /* in threaded mode, just stop transfer */
00613                     pthread_mutex_lock(&mutex);
00614                     transfer_online = transfer_online_local = FALSE;
00615                     pthread_mutex_unlock(&mutex);
00616                   } else {
00617                     /* in non-threaded mode, set end status and exit loop */
00618                     end_status = 1;
00619                     adin_purge(i);
00620                     goto break_input;
00621                   }
00622                   break;
00623 #else
00624                   /* in non-threaded mode, set end status and exit loop */
00625                   end_status = 1;
00626                   adin_purge(i);
00627                   goto break_input;
00628 #endif
00629                 case -1:                /* error occured in callback */
00630                   /* set end status and exit loop */
00631                   end_status = -1;
00632                   goto break_input;
00633                 }
00634               }
00635             }
00636             
00637           } else {              /* is_valid_data == TRUE */
00638             /******************************************************/
00639             /* process on, trigger on: we are in a speech segment */
00640             /******************************************************/
00641             
00642             if (nc > 0) {
00643               
00644               /*************************************/
00645               /* re-triggering in trailing silence */
00646               /*************************************/
00647               
00648 #ifdef THREAD_DEBUG
00649               printf("re-triggered\n");
00650 #endif
00651               /* reset noise counter */
00652               nc = 0;
00653 
00654 #ifdef TMP_FIX_200602
00655               if (ad_process != NULL
00656 #ifdef HAVE_PTHREAD
00657                   && (!enable_thread || !ignore_speech_while_recog || transfer_online_local)
00658 #endif
00659                   ) {
00660 #endif
00661               
00662               /*************************************************/
00663               /* process swap buffer stored while tail silence */
00664               /*************************************************/
00665               /* In trailing silence, the samples within the tail margin length
00666                  will be processed immediately, but samples after the tail
00667                  margin will not be processed, instead stored in swapbuf[].
00668                  If re-triggering occurs while in the trailing silence,
00669                  the swapped samples should be processed now to catch up
00670                  with current input
00671               */
00672               if (sblen > 0) {
00673 #ifdef THREAD_DEBUG
00674                 printf("callback for swapped %d samples\n", sblen);
00675 #endif
00676                 ad_process_ret = (*ad_process)(swapbuf, sblen);
00677                 sblen = 0;
00678                 switch(ad_process_ret) {
00679                 case 1:         /* segmentation notification from process callback */
00680 #ifdef HAVE_PTHREAD
00681                   if (enable_thread) {
00682                     /* in threaded mode, just stop transfer */
00683                     pthread_mutex_lock(&mutex);
00684                     transfer_online = transfer_online_local = FALSE;
00685                     pthread_mutex_unlock(&mutex);
00686                   } else {
00687                     /* in non-threaded mode, set end status and exit loop */
00688                     end_status = 1;
00689                     adin_purge(i);
00690                     goto break_input;
00691                   }
00692                   break;
00693 #else
00694                   /* in non-threaded mode, set end status and exit loop */
00695                   end_status = 1;
00696                   adin_purge(i);
00697                   goto break_input;
00698 #endif
00699                 case -1:                /* error occured in callback */
00700                   /* set end status and exit loop */
00701                   end_status = -1;
00702                   goto break_input;
00703                 }
00704               }
00705 #ifdef TMP_FIX_200602
00706               }
00707 #endif
00708             }
00709           } 
00710         } else if (is_valid_data == TRUE) {
00711           
00712           /*******************************************************/
00713           /* process on, trigger off: processing tailing silence */
00714           /*******************************************************/
00715           
00716 #ifdef THREAD_DEBUG
00717           printf("TRAILING SILENCE\n");
00718 #endif
00719           if (nc == 0) {
00720             /* start of tail silence: prepare valiables for start swapbuf[] */
00721             rest_tail = sbsize - c_length;
00722             sblen = 0;
00723 #ifdef THREAD_DEBUG
00724             printf("start tail silence, rest_tail = %d\n", rest_tail);
00725 #endif
00726           }
00727 
00728           /* increment noise counter */
00729           nc++;
00730         }
00731       } /* end of triggering handlers */
00732       
00733       
00734       /********************************************************************/
00735       /* process the current segment buffer[i...i+wstep] if process == on */
00736       /********************************************************************/
00737       
00738       if (adin_cut_on && is_valid_data && nc > 0 && rest_tail == 0) {
00739         
00740         /* The current trailing silence is now longer than the user-
00741            specified tail margin length, so the current samples
00742            should not be processed now.  But if 're-triggering'
00743            occurs in the trailing silence later, they should be processed
00744            then.  So we just store the overed samples in swapbuf[] and
00745            not process them now */
00746         
00747 #ifdef THREAD_DEBUG
00748         printf("tail silence over, store to swap buffer (nc=%d, rest_tail=%d, sblen=%d-%d)\n", nc, rest_tail, sblen, sblen+wstep);
00749 #endif
00750         if (sblen + wstep > sbsize) {
00751           j_printerr("Error: swapbuf exceeded!\n");
00752         }
00753         memcpy(&(swapbuf[sblen]), &(buffer[i]), wstep * sizeof(SP16));
00754         sblen += wstep;
00755         
00756       } else {
00757 
00758         /* we are in a normal speech segment (nc == 0), or
00759            trailing silence (shorter than tail margin length) (nc>0,rest_tail>0)
00760            The current trailing silence is shorter than the user-
00761            specified tail margin length, so the current samples
00762            should be processed now as same as the normal speech segment */
00763         
00764 #ifdef TMP_FIX_200602
00765         if (!adin_cut_on || is_valid_data == TRUE) {
00766 #else
00767         if(
00768            (!adin_cut_on || is_valid_data == TRUE)
00769 #ifdef HAVE_PTHREAD
00770            && (!enable_thread || !ignore_speech_while_recog || transfer_online_local)
00771 #endif
00772            ) {
00773 #endif
00774           if (nc > 0) {
00775             /* if we are in a trailing silence, decrease the counter to detect
00776              start of swapbuf[] above */
00777             if (rest_tail < wstep) rest_tail = 0;
00778             else rest_tail -= wstep;
00779 #ifdef THREAD_DEBUG
00780             printf("%d processed, rest_tail=%d\n", wstep, rest_tail);
00781 #endif
00782           }
00783 #ifdef TMP_FIX_200602
00784           if (ad_process != NULL
00785 #ifdef HAVE_PTHREAD
00786               && (!enable_thread || !ignore_speech_while_recog || transfer_online_local)
00787 #endif
00788               ) {
00789 
00790 #else
00791           if ( ad_process != NULL ) {
00792 #endif
00793 #ifdef THREAD_DEBUG
00794             printf("callback for input sample [%d-%d]\n", i, i+wstep);
00795 #endif
00796             /* call external function */
00797             ad_process_ret = (*ad_process)(&(buffer[i]),  wstep);
00798             switch(ad_process_ret) {
00799             case 1:             /* segmentation notification from process callback */
00800 #ifdef HAVE_PTHREAD
00801               if (enable_thread) {
00802                 /* in threaded mode, just stop transfer */
00803                 pthread_mutex_lock(&mutex);
00804                 transfer_online = transfer_online_local = FALSE;
00805                 pthread_mutex_unlock(&mutex);
00806               } else {
00807                 /* in non-threaded mode, set end status and exit loop */
00808                 adin_purge(i+wstep);
00809                 end_status = 1;
00810                 goto break_input;
00811               }
00812               break;
00813 #else
00814               /* in non-threaded mode, set end status and exit loop */
00815               adin_purge(i+wstep);
00816               end_status = 1;
00817               goto break_input;
00818 #endif
00819             case -1:            /* error occured in callback */
00820               /* set end status and exit loop */
00821               end_status = -1;
00822               goto break_input;
00823             }
00824           }
00825         }
00826       } /* end of current segment processing */
00827 
00828       
00829       if (adin_cut_on && is_valid_data && nc >= nc_max) {
00830         /*************************************/
00831         /* process on, trailing silence over */
00832         /* = end of input segment            */
00833         /*************************************/
00834 #ifdef THREAD_DEBUG
00835         printf("detect off\n");
00836 #endif
00837         /* end input by silence */
00838         is_valid_data = FALSE;  /* turn off processing */
00839         sblen = 0;
00840 #ifdef HAVE_PTHREAD
00841         if (enable_thread) { /* just stop transfer */
00842           pthread_mutex_lock(&mutex);
00843           transfer_online = transfer_online_local = FALSE;
00844           pthread_mutex_unlock(&mutex);
00845         } else {
00846           adin_purge(i+wstep);
00847           end_status = 1;
00848           goto break_input;
00849         }
00850 #else
00851         adin_purge(i+wstep);
00852         end_status = 1;
00853         goto break_input;
00854 #endif
00855       }
00856 
00857       /*********************************************************/
00858       /* end of processing buffer[0..current_len] by wstep step */
00859       /*********************************************************/
00860       i += wstep;               /* increment to next wstep samples */
00861     }
00862     
00863     /* purge processed samples and update queue */
00864     adin_purge(i);
00865 
00866     /* end of input by end of stream */
00867     if (end_of_stream && bp == 0) break;
00868   }
00869 
00870 break_input:
00871 
00872   /****************/
00873   /* pause input */
00874   /****************/
00875   /* stop speech input */
00876   if (ad_pause != NULL) {
00877     if ((*ad_pause)() == FALSE) {
00878       j_printerr("Error: failed to pause recording\n");
00879       end_status = -1;
00880     }
00881   }
00882 
00883   if (end_of_stream) {                  /* input already ends */
00884     if (bp == 0) {              /* rest buffer successfully flushed */
00885       /* reset status */
00886       if (adin_cut_on) end_count_zc_e();
00887       need_init = TRUE;         /* bufer status shoule be reset at next call */
00888     }
00889     end_status = (bp) ? 1 : 0;
00890   }
00891   
00892   return(end_status);
00893 }
00894 
00895 
00896 
00897 
00898 
00899 
00900 
00901 
00902 #ifdef HAVE_PTHREAD
00903 /***********************/
00904 /* threading functions */
00905 /***********************/
00906 
00907 /*************************/
00908 /* adin thread functions */
00909 /*************************/
00910 
00919 static int
00920 adin_store_buffer(SP16 *now, int len)
00921 {
00922   if (speechlen + len > MAXSPEECHLEN) {
00923     /* just mark as overflowed, and continue this thread */
00924     pthread_mutex_lock(&mutex);
00925     adinthread_buffer_overflowed = TRUE;
00926     pthread_mutex_unlock(&mutex);
00927     return(0);
00928   }
00929   pthread_mutex_lock(&mutex);
00930   memcpy(&(speech[speechlen]), now, len * sizeof(SP16));
00931   speechlen += len;
00932   pthread_mutex_unlock(&mutex);
00933 #ifdef THREAD_DEBUG
00934   printf("input: stored %d samples, total=%d\n", len, speechlen);
00935 #endif
00936   /* output progress bar in dots */
00937   /*if ((++dotcount) % 3 == 1) j_printerr(".");*/
00938   return(0);                    /* continue */
00939 }
00940 
00946 void
00947 adin_thread_input_main(void *dummy)
00948 {
00949   adin_cut(adin_store_buffer, NULL);
00950 }
00951 
00956 static void
00957 adin_thread_create()
00958 {
00959   /* init storing buffer */
00960   speechlen = 0;
00961   speech = (SP16 *)mymalloc(sizeof(SP16) * MAXSPEECHLEN);
00962 
00963   transfer_online = FALSE; /* tell adin-mic thread to wait at initial */
00964   adinthread_buffer_overflowed = FALSE;
00965 
00966   if (pthread_mutex_init(&(mutex), NULL) != 0) { /* error */
00967     j_error("Error: pthread: cannot initialize mutex\n");
00968   }
00969   if (pthread_create(&adin_thread, NULL, (void *)adin_thread_input_main, NULL) != 0) {
00970     j_error("Error: pthread: failed to create AD-in thread\n");
00971   }
00972   if (pthread_detach(adin_thread) != 0) { /* not join, run forever */
00973     j_error("Error: pthread: failed to detach AD-in thread\n");
00974   }
00975   j_printerr("AD-in thread created\n");
00976 }
00977 
00978 /****************************/
00979 /* process thread functions */
00980 /****************************/
00981 /* used for module mode: return value: -2 = input cancellation forced by control module */
00982 
00996 static int
00997 adin_thread_process(int (*ad_process)(SP16 *, int), int (*ad_check)())
00998 {
00999   int prev_len, nowlen;
01000   int ad_process_ret;
01001   int i;
01002   boolean overflowed_p;
01003   boolean transfer_online_local;
01004 
01005   /* reset storing buffer --- input while recognition will be ignored */
01006   pthread_mutex_lock(&mutex);
01007   /*if (speechlen == 0) transfer_online = TRUE;*/ /* tell adin-mic thread to start recording */
01008   transfer_online = TRUE;
01009 #ifdef THREAD_DEBUG
01010   printf("process: reset, speechlen = %d, online=%d\n", speechlen, transfer_online);
01011 #endif
01012   pthread_mutex_unlock(&mutex);
01013 
01014   /* main processing loop */
01015   prev_len = 0;
01016   for(;;) {
01017     /* get current length (locking) */
01018     pthread_mutex_lock(&mutex);
01019     nowlen = speechlen;
01020     overflowed_p = adinthread_buffer_overflowed;
01021     transfer_online_local = transfer_online;
01022     pthread_mutex_unlock(&mutex);
01023     /* check if other input thread has overflowed */
01024     if (overflowed_p) {
01025       j_printerr("Warning: too long input (> %d samples), segmented now\n", MAXSPEECHLEN);
01026       /* segment input here */
01027       pthread_mutex_lock(&mutex);
01028       adinthread_buffer_overflowed = FALSE;
01029       speechlen = 0;
01030       transfer_online = transfer_online_local = FALSE;
01031       pthread_mutex_unlock(&mutex);
01032       return(1);                /* return with segmented status */
01033     }
01034     /* callback poll */
01035     if (ad_check != NULL) {
01036       if ((i = (*ad_check)()) < 0) {
01037         if ((i == -1 && nowlen == 0) || i == -2) {
01038           pthread_mutex_lock(&mutex);
01039           transfer_online = transfer_online_local = FALSE;
01040           speechlen = 0;
01041           pthread_mutex_unlock(&mutex);
01042           return(-2);
01043         }
01044       }
01045     }
01046     if (prev_len < nowlen) {
01047 #ifdef THREAD_DEBUG
01048       printf("process: proceed [%d-%d]\n",prev_len, nowlen);
01049 #endif
01050       /* got new sample, process */
01051       /* As the speech[] buffer is monotonously increase,
01052          content of speech buffer [prev_len..nowlen] would not alter
01053          in both threads
01054          So locking is not needed while processing.
01055        */
01056       /*printf("main: read %d-%d\n", prev_len, nowlen);*/
01057       if (ad_process != NULL) {
01058         ad_process_ret = (*ad_process)(&(speech[prev_len]),  nowlen - prev_len);
01059 #ifdef THREAD_DEBUG
01060         printf("ad_process_ret=%d\n",ad_process_ret);
01061 #endif
01062         switch(ad_process_ret) {
01063         case 1:                 /* segmented */
01064           /* segmented by callback function */
01065           /* purge processed samples and keep transfering */
01066           pthread_mutex_lock(&mutex);
01067           if(speechlen > nowlen) {
01068             memmove(buffer, &(buffer[nowlen]), (speechlen - nowlen) * sizeof(SP16));
01069             speechlen = speechlen - nowlen;
01070           } else {
01071             speechlen = 0;
01072           }
01073           transfer_online = transfer_online_local = FALSE;
01074           pthread_mutex_unlock(&mutex);
01075           /* keep transfering */
01076           return(1);            /* return with segmented status */
01077         case -1:                /* error */
01078           pthread_mutex_lock(&mutex);
01079           transfer_online = transfer_online_local = FALSE;
01080           pthread_mutex_unlock(&mutex);
01081           return(-1);           /* return with error */
01082         }
01083       }
01084       prev_len = nowlen;
01085     } else {
01086       if (transfer_online_local == FALSE) {
01087         /* segmented by zero-cross */
01088         /* reset storing buffer for next input */
01089         pthread_mutex_lock(&mutex);
01090         speechlen = 0;
01091         pthread_mutex_unlock(&mutex);
01092         break;
01093       }
01094       usleep(100000);   /* wait = 0.1sec*/            
01095     }
01096   }
01097 
01098   /* as threading assumes infinite input */
01099   /* return value should be 1 (segmented) */
01100   return(1);
01101 }
01102 #endif /* HAVE_PTHREAD */
01103 
01104 
01105 
01106 
01125 int
01126 adin_go(int (*ad_process)(SP16 *, int), int (*ad_check)())
01127 {
01128 #ifdef HAVE_PTHREAD
01129   if (enable_thread) {
01130     return(adin_thread_process(ad_process, ad_check));
01131   }
01132 #endif
01133   return(adin_cut(ad_process, ad_check));
01134 }

Generated on Tue Dec 26 12:53:22 2006 for Julian by  doxygen 1.5.0