Julius 4.1.5
libjulius/src/adin-cut.c
説明を見る。
00001 
00101 /*
00102  * Copyright (c) 1991-2007 Kawahara Lab., Kyoto University
00103  * Copyright (c) 2000-2005 Shikano Lab., Nara Institute of Science and Technology
00104  * Copyright (c) 2005-2007 Julius project team, Nagoya Institute of Technology
00105  * All rights reserved
00106  */
00107 
00108 #include <julius/julius.h>
00109 #ifdef HAVE_PTHREAD
00110 #include <pthread.h>
00111 #endif
00112 
00114 #undef THREAD_DEBUG
00115 
00116 #define TMP_FIX_200602          
00117 
00137 boolean
00138 adin_setup_param(ADIn *adin, Jconf *jconf)
00139 {
00140   float samples_in_msec;
00141   int freq;
00142 
00143   if (jconf->input.sfreq <= 0) {
00144     jlog("ERROR: adin_setup_param: going to set smpfreq to %d\n", jconf->input.sfreq);
00145     return FALSE;
00146   }
00147   if (jconf->detect.silence_cut < 2) {
00148     adin->adin_cut_on = (jconf->detect.silence_cut == 1) ? TRUE : FALSE;
00149   } else {
00150     adin->adin_cut_on = adin->silence_cut_default;
00151   }
00152   adin->strip_flag = jconf->preprocess.strip_zero_sample;
00153   adin->thres = jconf->detect.level_thres;
00154 #ifdef HAVE_PTHREAD
00155   if (adin->enable_thread && jconf->decodeopt.segment) {
00156     adin->ignore_speech_while_recog = FALSE;
00157   } else {
00158     adin->ignore_speech_while_recog = TRUE;
00159   }
00160 #endif
00161   adin->need_zmean = jconf->preprocess.use_zmean;
00162   /* calc & set internal parameter from configuration */
00163   freq = jconf->input.sfreq;
00164   samples_in_msec = (float) freq / (float)1000.0;
00165   /* cycle buffer length = head margin length */
00166   adin->c_length = (int)((float)jconf->detect.head_margin_msec * samples_in_msec);      /* in msec. */
00167   /* compute zerocross trigger count threshold in the cycle buffer */
00168   adin->noise_zerocross = jconf->detect.zero_cross_num * adin->c_length / freq;
00169   /* variables that comes from the tail margin length (in wstep) */
00170   adin->nc_max = (int)((float)(jconf->detect.tail_margin_msec * samples_in_msec / (float)DEFAULT_WSTEP)) + 2;
00171   adin->sbsize = jconf->detect.tail_margin_msec * samples_in_msec + (adin->c_length * jconf->detect.zero_cross_num / 200);
00172   adin->c_offset = 0;
00173 
00174 #ifdef HAVE_PTHREAD
00175   adin->transfer_online = FALSE;
00176   adin->speech = NULL;
00177 #endif
00178 
00179   /**********************/
00180   /* initialize buffers */
00181   /**********************/
00182   adin->buffer = (SP16 *)mymalloc(sizeof(SP16) * MAXSPEECHLEN);
00183   adin->cbuf = (SP16 *)mymalloc(sizeof(SP16) * adin->c_length);
00184   adin->swapbuf = (SP16 *)mymalloc(sizeof(SP16) * adin->sbsize);
00185   if (adin->down_sample) {
00186     adin->io_rate = 3;          /* 48 / 16 (fixed) */
00187     adin->buffer48 = (SP16 *)mymalloc(sizeof(SP16) * MAXSPEECHLEN * adin->io_rate);
00188   }
00189   if (adin->adin_cut_on) {
00190     init_count_zc_e(&(adin->zc), adin->c_length);
00191   }
00192   
00193   adin->need_init = TRUE;
00194 
00195   adin->rehash = FALSE;
00196 
00197   return TRUE;
00198 
00199 }
00200 
00213 static void
00214 adin_purge(ADIn *a, int from)
00215 {
00216   if (from > 0 && a->current_len - from > 0) {
00217     memmove(a->buffer, &(a->buffer[from]), (a->current_len - from) * sizeof(SP16));
00218   }
00219   a->bp = a->current_len - from;
00220 }
00221 
00294 static int
00295 adin_cut(int (*ad_process)(SP16 *, int, Recog *), int (*ad_check)(Recog *), Recog *recog)
00296 {
00297   ADIn *a;
00298   int i;
00299   int ad_process_ret;
00300   int imax, len, cnt;
00301   int wstep;
00302   int end_status;       /* return value */
00303   boolean transfer_online_local;        /* local repository of transfer_online */
00304   int zc;               /* count of zero cross */
00305 
00306   a = recog->adin;
00307 
00308   /*
00309    * there are 3 buffers:
00310    *   temporary storage queue: buffer[]
00311    *   cycle buffer for zero-cross counting: (in zc_e)
00312    *   swap buffer for re-starting after short tail silence
00313    *
00314    * Each samples are first read to buffer[], then passed to count_zc_e()
00315    * to find trigger.  Samples between trigger and end of speech are 
00316    * passed to (*ad_process) with pointer to the first sample and its length.
00317    *
00318    */
00319 
00320   if (a->need_init) {
00321     a->bpmax = MAXSPEECHLEN;
00322     a->bp = 0;
00323     a->is_valid_data = FALSE;
00324     /* reset zero-cross status */
00325     if (a->adin_cut_on) {
00326       reset_count_zc_e(&(a->zc), a->thres, a->c_length, a->c_offset);
00327     }
00328     a->end_of_stream = FALSE;
00329     a->nc = 0;
00330     a->sblen = 0;
00331     a->need_init = FALSE;               /* for next call */
00332   }
00333 
00334   /****************/
00335   /* resume input */
00336   /****************/
00337   //  if (!a->adin_cut_on && a->is_valid_data == TRUE) {
00338   //    callback_exec(CALLBACK_EVENT_SPEECH_START, recog);
00339   //  }
00340 
00341   /*************/
00342   /* main loop */
00343   /*************/
00344   for (;;) {
00345 
00346     /****************************/
00347     /* read in new speech input */
00348     /****************************/
00349     if (a->end_of_stream) {
00350       /* already reaches end of stream, just process the rest */
00351       a->current_len = a->bp;
00352     } else {
00353       /*****************************************************/
00354       /* get samples from input device to temporary buffer */
00355       /*****************************************************/
00356       /* buffer[0..bp] is the current remaining samples */
00357       /*
00358         mic input - samples exist in a device buffer
00359         tcpip input - samples exist in a socket
00360         file input - samples in a file
00361            
00362         Return value is the number of read samples.
00363         If no data exists in the device (in case of mic input), ad_read()
00364         will return 0.  If reached end of stream (in case end of file or
00365         receive end ack from tcpip client), it will return -1.
00366         If error, returns -2.
00367       */
00368       if (a->down_sample) {
00369         /* get 48kHz samples to temporal buffer */
00370         cnt = (*(a->ad_read))(a->buffer48, (a->bpmax - a->bp) * a->io_rate);
00371       } else {
00372         cnt = (*(a->ad_read))(&(a->buffer[a->bp]), a->bpmax - a->bp);
00373       }
00374       if (cnt < 0) {            /* end of stream / segment or error */
00375         /* set the end status */
00376         switch(cnt) {
00377         case -1:                /* end of stream */
00378           a->input_side_segment = FALSE;
00379           end_status = 0;
00380           break;
00381         case -2:
00382           a->input_side_segment = FALSE;
00383           end_status = -1;
00384           break;
00385         case -3:
00386           a->input_side_segment = TRUE;
00387           end_status = 0;
00388         }
00389         /* now the input has been ended, 
00390            we should not get further speech input in the next loop, 
00391            instead just process the samples in the temporary buffer until
00392            the entire data is processed. */
00393         a->end_of_stream = TRUE;                
00394         cnt = 0;                        /* no new input */
00395         /* in case the first trial of ad_read() fails, exit this loop */
00396         if (a->bp == 0) break;
00397       }
00398       if (a->down_sample && cnt != 0) {
00399         /* convert to 16kHz  */
00400         cnt = ds48to16(&(a->buffer[a->bp]), a->buffer48, cnt, a->bpmax - a->bp, a->ds);
00401         if (cnt < 0) {          /* conversion error */
00402           jlog("ERROR: adin_cut: error in down sampling\n");
00403           end_status = -1;
00404           a->end_of_stream = TRUE;
00405           cnt = 0;
00406           if (a->bp == 0) break;
00407         }
00408       }
00409 
00410       /*************************************************/
00411       /* execute callback here for incoming raw data stream.*/
00412       /* the content of buffer[bp...bp+cnt-1] or the   */
00413       /* length can be modified in the functions.      */
00414       /*************************************************/
00415       if (cnt > 0) {
00416 #ifdef ENABLE_PLUGIN
00417         plugin_exec_adin_captured(&(a->buffer[a->bp]), cnt);
00418 #endif
00419         callback_exec_adin(CALLBACK_ADIN_CAPTURED, recog, &(a->buffer[a->bp]), cnt);
00420         /* record total number of captured samples */
00421         a->total_captured_len += cnt;
00422       }
00423 
00424       /*************************************************/
00425       /* some speech processing for the incoming input */
00426       /*************************************************/
00427       if (cnt > 0) {
00428         if (a->strip_flag) {
00429           /* strip off successive zero samples */
00430           len = strip_zero(&(a->buffer[a->bp]), cnt);
00431           if (len != cnt) cnt = len;
00432         }
00433         if (a->need_zmean) {
00434           /* remove DC offset */
00435           sub_zmean(&(a->buffer[a->bp]), cnt);
00436         }
00437       }
00438       
00439       /* current len = current samples in buffer */
00440       a->current_len = a->bp + cnt;
00441     }
00442 #ifdef THREAD_DEBUG
00443     if (a->end_of_stream) {
00444       jlog("DEBUG: adin_cut: stream already ended\n");
00445     }
00446     if (cnt > 0) {
00447       jlog("DEBUG: adin_cut: get %d samples [%d-%d]\n", a->current_len - a->bp, a->bp, a->current_len);
00448     }
00449 #endif
00450 
00451     /**************************************************/
00452     /* call the periodic callback (non threaded mode) */
00453     /*************************************************/
00454     /* this function is mainly for periodic checking of incoming command
00455        in module mode */
00456     /* in threaded mode, this will be done in process thread, not here in adin thread */
00457     if (ad_check != NULL
00458 #ifdef HAVE_PTHREAD
00459         && !a->enable_thread
00460 #endif
00461         ) {
00462       /* if ad_check() returns value < 0, termination of speech input is required */
00463       if ((i = (*ad_check)(recog)) < 0) { /* -1: soft termination -2: hard termination */
00464         //      if ((i == -1 && current_len == 0) || i == -2) {
00465         if (i == -2 ||
00466             (i == -1 && a->is_valid_data == FALSE)) {
00467           end_status = -2;      /* recognition terminated by outer function */
00468           /* execute callback */
00469           if (a->current_len > 0) {
00470             callback_exec(CALLBACK_EVENT_SPEECH_STOP, recog);
00471           }
00472           a->need_init = TRUE; /* bufer status shoule be reset at next call */
00473           goto break_input;
00474         }
00475       }
00476     }
00477 
00478     /***********************************************************************/
00479     /* if no data has got but not end of stream, repeat next input samples */
00480     /***********************************************************************/
00481     if (a->current_len == 0) continue;
00482 
00483     /* When not adin_cut mode, all incoming data is valid.
00484        So is_valid_data should be set to TRUE when some input first comes
00485        till this input ends.  So, if some data comes, set is_valid_data to
00486        TRUE here. */ 
00487     if (!a->adin_cut_on && a->is_valid_data == FALSE && a->current_len > 0) {
00488       a->is_valid_data = TRUE;
00489       callback_exec(CALLBACK_EVENT_SPEECH_START, recog);
00490     }
00491 
00492     /******************************************************/
00493     /* prepare for processing samples in temporary buffer */
00494     /******************************************************/
00495     
00496     wstep = DEFAULT_WSTEP;      /* process unit (should be smaller than cycle buffer) */
00497 
00498     /* imax: total length that should be processed at one ad_read() call */
00499     /* if in real-time mode and not threaded, recognition process 
00500        will be called and executed as the ad_process() callback within
00501        this function.  If the recognition speed is over the real time,
00502        processing all the input samples at the loop below may result in the
00503        significant delay of getting next input, that may result in the buffer
00504        overflow of the device (namely a microphone device will suffer from
00505        this). So, in non-threaded mode, in order to avoid buffer overflow and
00506        input frame dropping, we will leave here by processing 
00507        only one segment [0..wstep], and leave the rest in the temporary buffer.
00508     */
00509 #ifdef HAVE_PTHREAD
00510     if (a->enable_thread) imax = a->current_len; /* process whole */
00511     else imax = (a->current_len < wstep) ? a->current_len : wstep; /* one step */
00512 #else
00513     imax = (a->current_len < wstep) ? a->current_len : wstep;   /* one step */
00514 #endif
00515     
00516     /* wstep: unit length for the loop below */
00517     if (wstep > a->current_len) wstep = a->current_len;
00518 
00519 #ifdef THREAD_DEBUG
00520     jlog("DEBUG: process %d samples by %d step\n", imax, wstep);
00521 #endif
00522 
00523 #ifdef HAVE_PTHREAD
00524     if (a->enable_thread) {
00525       /* get transfer status to local */
00526       pthread_mutex_lock(&(a->mutex));
00527       transfer_online_local = a->transfer_online;
00528       pthread_mutex_unlock(&(a->mutex));
00529     }
00530 #endif
00531 
00532     /*********************************************************/
00533     /* start processing buffer[0..current_len] by wstep step */
00534     /*********************************************************/
00535     i = 0;
00536     while (i + wstep <= imax) {
00537 
00538       if (a->adin_cut_on) {
00539 
00540         /********************/
00541         /* check triggering */
00542         /********************/
00543         /* the cycle buffer in count_zc_e() holds the last
00544            samples of (head_margin) miliseconds, and the zerocross
00545            over the threshold level are counted within the cycle buffer */
00546         
00547         /* store the new data to cycle buffer and update the count */
00548         /* return zero-cross num in the cycle buffer */
00549         zc = count_zc_e(&(a->zc), &(a->buffer[i]), wstep);
00550         
00551         if (zc > a->noise_zerocross) { /* now triggering */
00552           
00553           if (a->is_valid_data == FALSE) {
00554             /*****************************************************/
00555             /* process off, trigger on: detect speech triggering */
00556             /*****************************************************/
00557             a->is_valid_data = TRUE;   /* start processing */
00558             a->nc = 0;
00559 #ifdef THREAD_DEBUG
00560             jlog("DEBUG: detect on\n");
00561 #endif
00562             /* record time */
00563             a->last_trigger_sample = a->total_captured_len - a->current_len + i + wstep - a->zc.valid_len;
00564             callback_exec(CALLBACK_EVENT_SPEECH_START, recog);
00565 
00566             /****************************************/
00567             /* flush samples stored in cycle buffer */
00568             /****************************************/
00569             /* (last (head_margin) msec samples */
00570             /* if threaded mode, processing means storing them to speech[].
00571                if ignore_speech_while_recog is on (default), ignore the data
00572                if transfer is offline (=while processing second pass).
00573                Else, datas are stored even if transfer is offline */
00574             if ( ad_process != NULL
00575 #ifdef HAVE_PTHREAD
00576                  && (!a->enable_thread || !a->ignore_speech_while_recog || transfer_online_local)
00577 #endif
00578                  ) {
00579               /* copy content of cycle buffer to cbuf */
00580               zc_copy_buffer(&(a->zc), a->cbuf, &len);
00581               /* Note that the last 'wstep' samples are the same as
00582                  the current samples 'buffer[i..i+wstep]', and
00583                  they will be processed later.  So, here only the samples
00584                  cbuf[0...len-wstep] will be processed
00585               */
00586               if (len - wstep > 0) {
00587 #ifdef THREAD_DEBUG
00588                 jlog("DEBUG: callback for buffered samples (%d bytes)\n", len - wstep);
00589 #endif
00590 #ifdef ENABLE_PLUGIN
00591                 plugin_exec_adin_triggered(a->cbuf, len - wstep);
00592 #endif
00593                 callback_exec_adin(CALLBACK_ADIN_TRIGGERED, recog, a->cbuf, len - wstep);
00594                 ad_process_ret = (*ad_process)(a->cbuf, len - wstep, recog);
00595                 switch(ad_process_ret) {
00596                 case 1:         /* segmentation notification from process callback */
00597 #ifdef HAVE_PTHREAD
00598                   if (a->enable_thread) {
00599                     /* in threaded mode, just stop transfer */
00600                     pthread_mutex_lock(&(a->mutex));
00601                     a->transfer_online = transfer_online_local = FALSE;
00602                     pthread_mutex_unlock(&(a->mutex));
00603                   } else {
00604                     /* in non-threaded mode, set end status and exit loop */
00605                     end_status = 2;
00606                     adin_purge(a, i);
00607                     goto break_input;
00608                   }
00609                   break;
00610 #else
00611                   /* in non-threaded mode, set end status and exit loop */
00612                   end_status = 2;
00613                   adin_purge(a, i);
00614                   goto break_input;
00615 #endif
00616                 case -1:                /* error occured in callback */
00617                   /* set end status and exit loop */
00618                   end_status = -1;
00619                   goto break_input;
00620                 }
00621               }
00622             }
00623             
00624           } else {              /* is_valid_data == TRUE */
00625             /******************************************************/
00626             /* process on, trigger on: we are in a speech segment */
00627             /******************************************************/
00628             
00629             if (a->nc > 0) {
00630               
00631               /*************************************/
00632               /* re-triggering in trailing silence */
00633               /*************************************/
00634               
00635 #ifdef THREAD_DEBUG
00636               jlog("DEBUG: re-triggered\n");
00637 #endif
00638               /* reset noise counter */
00639               a->nc = 0;
00640 
00641 #ifdef TMP_FIX_200602
00642               if (ad_process != NULL
00643 #ifdef HAVE_PTHREAD
00644                   && (!a->enable_thread || !a->ignore_speech_while_recog || transfer_online_local)
00645 #endif
00646                   ) {
00647 #endif
00648               
00649               /*************************************************/
00650               /* process swap buffer stored while tail silence */
00651               /*************************************************/
00652               /* In trailing silence, the samples within the tail margin length
00653                  will be processed immediately, but samples after the tail
00654                  margin will not be processed, instead stored in swapbuf[].
00655                  If re-triggering occurs while in the trailing silence,
00656                  the swapped samples should be processed now to catch up
00657                  with current input
00658               */
00659               if (a->sblen > 0) {
00660 #ifdef THREAD_DEBUG
00661                 jlog("DEBUG: callback for swapped %d samples\n", a->sblen);
00662 #endif
00663 #ifdef ENABLE_PLUGIN
00664                 plugin_exec_adin_triggered(a->swapbuf, a->sblen);
00665 #endif
00666                 callback_exec_adin(CALLBACK_ADIN_TRIGGERED, recog, a->swapbuf, a->sblen);
00667                 ad_process_ret = (*ad_process)(a->swapbuf, a->sblen, recog);
00668                 a->sblen = 0;
00669                 switch(ad_process_ret) {
00670                 case 1:         /* segmentation notification from process callback */
00671 #ifdef HAVE_PTHREAD
00672                   if (a->enable_thread) {
00673                     /* in threaded mode, just stop transfer */
00674                     pthread_mutex_lock(&(a->mutex));
00675                     a->transfer_online = transfer_online_local = FALSE;
00676                     pthread_mutex_unlock(&(a->mutex));
00677                   } else {
00678                     /* in non-threaded mode, set end status and exit loop */
00679                     end_status = 2;
00680                     adin_purge(a, i);
00681                     goto break_input;
00682                   }
00683                   break;
00684 #else
00685                   /* in non-threaded mode, set end status and exit loop */
00686                   end_status = 2;
00687                   adin_purge(a, i);
00688                   goto break_input;
00689 #endif
00690                 case -1:                /* error occured in callback */
00691                   /* set end status and exit loop */
00692                   end_status = -1;
00693                   goto break_input;
00694                 }
00695               }
00696 #ifdef TMP_FIX_200602
00697               }
00698 #endif
00699             }
00700           } 
00701         } else if (a->is_valid_data == TRUE) {
00702           
00703           /*******************************************************/
00704           /* process on, trigger off: processing tailing silence */
00705           /*******************************************************/
00706           
00707 #ifdef THREAD_DEBUG
00708           jlog("DEBUG: TRAILING SILENCE\n");
00709 #endif
00710           if (a->nc == 0) {
00711             /* start of tail silence: prepare valiables for start swapbuf[] */
00712             a->rest_tail = a->sbsize - a->c_length;
00713             a->sblen = 0;
00714 #ifdef THREAD_DEBUG
00715             jlog("DEBUG: start tail silence, rest_tail = %d\n", a->rest_tail);
00716 #endif
00717           }
00718 
00719           /* increment noise counter */
00720           a->nc++;
00721         }
00722       } /* end of triggering handlers */
00723       
00724       
00725       /********************************************************************/
00726       /* process the current segment buffer[i...i+wstep] if process == on */
00727       /********************************************************************/
00728       
00729       if (a->adin_cut_on && a->is_valid_data && a->nc > 0 && a->rest_tail == 0) {
00730         
00731         /* The current trailing silence is now longer than the user-
00732            specified tail margin length, so the current samples
00733            should not be processed now.  But if 're-triggering'
00734            occurs in the trailing silence later, they should be processed
00735            then.  So we just store the overed samples in swapbuf[] and
00736            not process them now */
00737         
00738 #ifdef THREAD_DEBUG
00739         jlog("DEBUG: tail silence over, store to swap buffer (nc=%d, rest_tail=%d, sblen=%d-%d)\n", a->nc, a->rest_tail, a->sblen, a->sblen+wstep);
00740 #endif
00741         if (a->sblen + wstep > a->sbsize) {
00742           jlog("ERROR: adin_cut: swap buffer for re-triggering overflow\n");
00743         }
00744         memcpy(&(a->swapbuf[a->sblen]), &(a->buffer[i]), wstep * sizeof(SP16));
00745         a->sblen += wstep;
00746         
00747       } else {
00748 
00749         /* we are in a normal speech segment (nc == 0), or
00750            trailing silence (shorter than tail margin length) (nc>0,rest_tail>0)
00751            The current trailing silence is shorter than the user-
00752            specified tail margin length, so the current samples
00753            should be processed now as same as the normal speech segment */
00754         
00755 #ifdef TMP_FIX_200602
00756         if (!a->adin_cut_on || a->is_valid_data == TRUE) {
00757 #else
00758         if(
00759            (!a->adin_cut_on || a->is_valid_data == TRUE)
00760 #ifdef HAVE_PTHREAD
00761            && (!a->enable_thread || !a->ignore_speech_while_recog || transfer_online_local)
00762 #endif
00763            ) {
00764 #endif
00765           if (a->nc > 0) {
00766             /* if we are in a trailing silence, decrease the counter to detect
00767              start of swapbuf[] above */
00768             if (a->rest_tail < wstep) a->rest_tail = 0;
00769             else a->rest_tail -= wstep;
00770 #ifdef THREAD_DEBUG
00771             jlog("DEBUG: %d processed, rest_tail=%d\n", wstep, a->rest_tail);
00772 #endif
00773           }
00774 #ifdef TMP_FIX_200602
00775           if (ad_process != NULL
00776 #ifdef HAVE_PTHREAD
00777               && (!a->enable_thread || !a->ignore_speech_while_recog || transfer_online_local)
00778 #endif
00779               ) {
00780 
00781 #else
00782           if ( ad_process != NULL ) {
00783 #endif
00784 #ifdef THREAD_DEBUG
00785             jlog("DEBUG: callback for input sample [%d-%d]\n", i, i+wstep);
00786 #endif
00787             /* call external function */
00788 #ifdef ENABLE_PLUGIN
00789             plugin_exec_adin_triggered(&(a->buffer[i]), wstep);
00790 #endif
00791             callback_exec_adin(CALLBACK_ADIN_TRIGGERED, recog, &(a->buffer[i]), wstep);
00792             ad_process_ret = (*ad_process)(&(a->buffer[i]), wstep, recog);
00793             switch(ad_process_ret) {
00794             case 1:             /* segmentation notification from process callback */
00795 #ifdef HAVE_PTHREAD
00796               if (a->enable_thread) {
00797                 /* in threaded mode, just stop transfer */
00798                 pthread_mutex_lock(&(a->mutex));
00799                 a->transfer_online = transfer_online_local = FALSE;
00800                 pthread_mutex_unlock(&(a->mutex));
00801               } else {
00802                 /* in non-threaded mode, set end status and exit loop */
00803                 adin_purge(a, i+wstep);
00804                 end_status = 2;
00805                 goto break_input;
00806               }
00807               break;
00808 #else
00809               /* in non-threaded mode, set end status and exit loop */
00810               adin_purge(a, i+wstep);
00811               end_status = 2;
00812               goto break_input;
00813 #endif
00814             case -1:            /* error occured in callback */
00815               /* set end status and exit loop */
00816               end_status = -1;
00817               goto break_input;
00818             }
00819           }
00820         }
00821       } /* end of current segment processing */
00822 
00823       
00824       if (a->adin_cut_on && a->is_valid_data && a->nc >= a->nc_max) {
00825         /*************************************/
00826         /* process on, trailing silence over */
00827         /* = end of input segment            */
00828         /*************************************/
00829 #ifdef THREAD_DEBUG
00830         jlog("DEBUG: detect off\n");
00831 #endif
00832         /* end input by silence */
00833         a->is_valid_data = FALSE;       /* turn off processing */
00834         a->sblen = 0;
00835         callback_exec(CALLBACK_EVENT_SPEECH_STOP, recog);
00836 #ifdef HAVE_PTHREAD
00837         if (a->enable_thread) { /* just stop transfer */
00838           pthread_mutex_lock(&(a->mutex));
00839           a->transfer_online = transfer_online_local = FALSE;
00840           pthread_mutex_unlock(&(a->mutex));
00841         } else {
00842           adin_purge(a, i+wstep);
00843           end_status = 1;
00844           goto break_input;
00845         }
00846 #else
00847         adin_purge(a, i+wstep);
00848         end_status = 1;
00849         goto break_input;
00850 #endif
00851       }
00852 
00853       /*********************************************************/
00854       /* end of processing buffer[0..current_len] by wstep step */
00855       /*********************************************************/
00856       i += wstep;               /* increment to next wstep samples */
00857     }
00858     
00859     /* purge processed samples and update queue */
00860     adin_purge(a, i);
00861 
00862     /* end of input by end of stream */
00863     if (a->end_of_stream && a->bp == 0) break;
00864   }
00865 
00866 break_input:
00867 
00868   /****************/
00869   /* pause input */
00870   /****************/
00871   if (a->end_of_stream) {                       /* input already ends */
00872     /* execute callback */
00873     callback_exec(CALLBACK_EVENT_SPEECH_STOP, recog);
00874     if (a->bp == 0) {           /* rest buffer successfully flushed */
00875       /* reset status */
00876       a->need_init = TRUE;              /* bufer status shoule be reset at next call */
00877     }
00878     end_status = (a->bp) ? 1 : 0;
00879   }
00880   
00881   return(end_status);
00882 }
00883 
00884 #ifdef HAVE_PTHREAD
00885 /***********************/
00886 /* threading functions */
00887 /***********************/
00888 
00889 /*************************/
00890 /* adin thread functions */
00891 /*************************/
00892 
00907 static int
00908 adin_store_buffer(SP16 *now, int len, Recog *recog)
00909 {
00910   ADIn *a;
00911 
00912   a = recog->adin;
00913   if (a->speechlen + len > MAXSPEECHLEN) {
00914     /* just mark as overflowed, and continue this thread */
00915     pthread_mutex_lock(&(a->mutex));
00916     a->adinthread_buffer_overflowed = TRUE;
00917     pthread_mutex_unlock(&(a->mutex));
00918     return(0);
00919   }
00920   pthread_mutex_lock(&(a->mutex));
00921   memcpy(&(a->speech[a->speechlen]), now, len * sizeof(SP16));
00922   a->speechlen += len;
00923   pthread_mutex_unlock(&(a->mutex));
00924 #ifdef THREAD_DEBUG
00925   jlog("DEBUG: input: stored %d samples, total=%d\n", len, a->speechlen);
00926 #endif
00927 
00928   return(0);                    /* continue */
00929 }
00930 
00941 static void
00942 adin_thread_input_main(void *dummy)
00943 {
00944   Recog *recog;
00945   int ret;
00946 
00947   recog = dummy;
00948 
00949   ret = adin_cut(adin_store_buffer, NULL, recog);
00950 
00951   if (ret == -1) {              /* error */
00952     jlog("Error: adin thread exit with error\n");
00953   } else if (ret == 0) {        /* EOF */
00954     jlog("Stat: adin thread end with EOF\n");
00955   }
00956   recog->adin->adinthread_ended = TRUE;
00957 
00958   /* return to end this thread */
00959 }
00960 
00973 boolean
00974 adin_thread_create(Recog *recog)
00975 {
00976   ADIn *a;
00977 
00978   a = recog->adin;
00979 
00980   /* init storing buffer */
00981   a->speech = (SP16 *)mymalloc(sizeof(SP16) * MAXSPEECHLEN);
00982   a->speechlen = 0;
00983 
00984   a->transfer_online = FALSE; /* tell adin-mic thread to wait at initial */
00985   a->adinthread_buffer_overflowed = FALSE;
00986   a->adinthread_ended = FALSE;
00987 
00988   if (pthread_mutex_init(&(a->mutex), NULL) != 0) { /* error */
00989     jlog("ERROR: adin_thread_create: failed to initialize mutex\n");
00990     return FALSE;
00991   }
00992   if (pthread_create(&(recog->adin->adin_thread), NULL, (void *)adin_thread_input_main, recog) != 0) {
00993     jlog("ERROR: adin_thread_create: failed to create AD-in thread\n");
00994     return FALSE;
00995   }
00996   if (pthread_detach(recog->adin->adin_thread) != 0) { /* not join, run forever */
00997     jlog("ERROR: adin_thread_create: failed to detach AD-in thread\n");
00998     return FALSE;
00999   }
01000   jlog("STAT: AD-in thread created\n");
01001   return TRUE;
01002 }
01003 
01016 boolean
01017 adin_thread_cancel(Recog *recog)
01018 {
01019   ADIn *a;
01020   int ret;
01021 
01022   if (recog->adin->adinthread_ended) return TRUE;
01023 
01024   ret = pthread_cancel(recog->adin->adin_thread);
01025   if (ret == 0) {
01026     jlog("STAT: AD-in thread deleted\n");
01027   } else {
01028     if (ret == ESRCH) {
01029       jlog("STAT: adin_thread_cancel: no A/D-in thread\n");
01030     } else {
01031       jlog("Error: adin_thread_cancel: failed to cancel A/D-in thread\n");
01032       return FALSE;
01033     }
01034   }
01035   recog->adin->adinthread_ended = TRUE;
01036   return TRUE;
01037 }
01038 
01039 /****************************/
01040 /* process thread functions */
01041 /****************************/
01042 
01067 static int
01068 adin_thread_process(int (*ad_process)(SP16 *, int, Recog *), int (*ad_check)(Recog *), Recog *recog)
01069 {
01070   int prev_len, nowlen;
01071   int ad_process_ret;
01072   int i;
01073   boolean overflowed_p;
01074   boolean transfer_online_local;
01075   boolean ended_p;
01076   ADIn *a;
01077 
01078   a = recog->adin;
01079 
01080   /* reset storing buffer --- input while recognition will be ignored */
01081   pthread_mutex_lock(&(a->mutex));
01082   /*if (speechlen == 0) transfer_online = TRUE;*/ /* tell adin-mic thread to start recording */
01083   a->transfer_online = TRUE;
01084 #ifdef THREAD_DEBUG
01085   jlog("DEBUG: process: reset, speechlen = %d, online=%d\n", a->speechlen, a->transfer_online);
01086 #endif
01087   pthread_mutex_unlock(&(a->mutex));
01088 
01089   /* main processing loop */
01090   prev_len = 0;
01091   for(;;) {
01092     /* get current length (locking) */
01093     pthread_mutex_lock(&(a->mutex));
01094     nowlen = a->speechlen;
01095     overflowed_p = a->adinthread_buffer_overflowed;
01096     transfer_online_local = a->transfer_online;
01097     ended_p = a->adinthread_ended;
01098     pthread_mutex_unlock(&(a->mutex));
01099     /* check if thread is alive */
01100     if (ended_p) {
01101       /* adin thread has already exited, so return EOF to stop this input */
01102       return(0);
01103     }
01104     /* check if other input thread has overflowed */
01105     if (overflowed_p) {
01106       jlog("WARNING: adin_thread_process: too long input (> %d samples), segmented now\n", MAXSPEECHLEN);
01107       /* segment input here */
01108       pthread_mutex_lock(&(a->mutex));
01109       a->adinthread_buffer_overflowed = FALSE;
01110       a->speechlen = 0;
01111       a->transfer_online = transfer_online_local = FALSE;
01112       pthread_mutex_unlock(&(a->mutex));
01113       return(1);                /* return with segmented status */
01114     }
01115     /* callback poll */
01116     if (ad_check != NULL) {
01117       if ((i = (*(ad_check))(recog)) < 0) {
01118         if ((i == -1 && nowlen == 0) || i == -2) {
01119           pthread_mutex_lock(&(a->mutex));
01120           a->transfer_online = transfer_online_local = FALSE;
01121           a->speechlen = 0;
01122           pthread_mutex_unlock(&(a->mutex));
01123           return(-2);
01124         }
01125       }
01126     }
01127     if (prev_len < nowlen) {
01128 #ifdef THREAD_DEBUG
01129       jlog("DEBUG: process: proceed [%d-%d]\n",prev_len, nowlen);
01130 #endif
01131       /* got new sample, process */
01132       /* As the speech[] buffer is monotonously increase,
01133          content of speech buffer [prev_len..nowlen] would not alter
01134          in both threads
01135          So locking is not needed while processing.
01136        */
01137       /*jlog("DEBUG: main: read %d-%d\n", prev_len, nowlen);*/
01138       if (ad_process != NULL) {
01139         ad_process_ret = (*ad_process)(&(a->speech[prev_len]), nowlen - prev_len, recog);
01140 #ifdef THREAD_DEBUG
01141         jlog("DEBUG: ad_process_ret=%d\n", ad_process_ret);
01142 #endif
01143         switch(ad_process_ret) {
01144         case 1:                 /* segmented */
01145           /* segmented by callback function */
01146           /* purge processed samples and keep transfering */
01147           pthread_mutex_lock(&(a->mutex));
01148           if(a->speechlen > nowlen) {
01149             memmove(a->speech, &(a->speech[nowlen]), (a->speechlen - nowlen) * sizeof(SP16));
01150             a->speechlen -= nowlen;
01151           } else {
01152             a->speechlen = 0;
01153           }
01154           a->transfer_online = transfer_online_local = FALSE;
01155           pthread_mutex_unlock(&(a->mutex));
01156           /* keep transfering */
01157           return(2);            /* return with segmented status */
01158         case -1:                /* error */
01159           pthread_mutex_lock(&(a->mutex));
01160           a->transfer_online = transfer_online_local = FALSE;
01161           pthread_mutex_unlock(&(a->mutex));
01162           return(-1);           /* return with error */
01163         }
01164       }
01165       if (a->rehash) {
01166         /* rehash */
01167         pthread_mutex_lock(&(a->mutex));
01168         if (debug2_flag) jlog("STAT: adin_cut: rehash from %d to %d\n", a->speechlen, a->speechlen - prev_len);
01169         a->speechlen -= prev_len;
01170         nowlen -= prev_len;
01171         memmove(a->speech, &(a->speech[prev_len]), a->speechlen * sizeof(SP16));
01172         pthread_mutex_unlock(&(a->mutex));
01173         a->rehash = FALSE;
01174       }
01175       prev_len = nowlen;
01176     } else {
01177       if (transfer_online_local == FALSE) {
01178         /* segmented by zero-cross */
01179         /* reset storing buffer for next input */
01180         pthread_mutex_lock(&(a->mutex));
01181         a->speechlen = 0;
01182         pthread_mutex_unlock(&(a->mutex));
01183         break;
01184       }
01185       usleep(50000);   /* wait = 0.05sec*/            
01186     }
01187   }
01188 
01189   /* as threading assumes infinite input */
01190   /* return value should be 1 (segmented) */
01191   return(1);
01192 }
01193 #endif /* HAVE_PTHREAD */
01194 
01195 
01196 
01197 
01231 int
01232 adin_go(int (*ad_process)(SP16 *, int, Recog *), int (*ad_check)(Recog *), Recog *recog)
01233 {
01234   /* output listening start message */
01235   callback_exec(CALLBACK_EVENT_SPEECH_READY, recog);
01236 #ifdef HAVE_PTHREAD
01237   if (recog->adin->enable_thread) {
01238     return(adin_thread_process(ad_process, ad_check, recog));
01239   }
01240 #endif
01241   return(adin_cut(ad_process, ad_check, recog));
01242 }
01243 
01262 boolean
01263 adin_standby(ADIn *a, int freq, void *arg)
01264 {
01265   if (a->need_zmean) zmean_reset();
01266   if (a->ad_standby != NULL) return(a->ad_standby(freq, arg));
01267   return TRUE;
01268 }
01286 boolean
01287 adin_begin(ADIn *a, char *file_or_dev_name)
01288 {
01289   if (debug2_flag && a->input_side_segment) jlog("Stat: adin_begin: skip\n");
01290   if (a->input_side_segment == FALSE) {
01291     a->total_captured_len = 0;
01292     if (a->need_zmean) zmean_reset();
01293     if (a->ad_begin != NULL) return(a->ad_begin(file_or_dev_name));
01294   }
01295   return TRUE;
01296 }
01312 boolean
01313 adin_end(ADIn *a)
01314 {
01315   if (debug2_flag && a->input_side_segment) jlog("Stat: adin_end: skip\n");
01316   if (a->input_side_segment == FALSE) {
01317     if (a->ad_end != NULL) return(a->ad_end());
01318   }
01319   return TRUE;
01320 }
01321 
01336 void
01337 adin_free_param(Recog *recog)
01338 {
01339   ADIn *a;
01340 
01341   a = recog->adin;
01342 
01343   if (a->ds) {
01344     ds48to16_free(a->ds);
01345     a->ds = NULL;
01346   }
01347   if (a->adin_cut_on) {
01348     free_count_zc_e(&(a->zc));
01349   }
01350   if (a->down_sample) {
01351     free(a->buffer48);
01352   }
01353   free(a->swapbuf);
01354   free(a->cbuf);
01355   free(a->buffer);
01356 #ifdef HAVE_PTHREAD
01357   if (a->speech) free(a->speech);
01358 #endif
01359 }
01360 
01361 /* end of file */