Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

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

Generated on Tue Mar 28 16:01:39 2006 for Julius by  doxygen 1.4.2