Julius 4.2
libjulius/src/adin-cut.c
説明を見る。
00001 
00101 /*
00102  * Copyright (c) 1991-2011 Kawahara Lab., Kyoto University
00103  * Copyright (c) 2000-2005 Shikano Lab., Nara Institute of Science and Technology
00104  * Copyright (c) 2005-2011 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 = 0;   /* 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. If the device requests segmentation, returns -3.
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     if (end_status >= 0) {
00879       end_status = (a->bp) ? 1 : 0;
00880     }
00881   }
00882   
00883   return(end_status);
00884 }
00885 
00886 #ifdef HAVE_PTHREAD
00887 /***********************/
00888 /* threading functions */
00889 /***********************/
00890 
00891 /*************************/
00892 /* adin thread functions */
00893 /*************************/
00894 
00909 static int
00910 adin_store_buffer(SP16 *now, int len, Recog *recog)
00911 {
00912   ADIn *a;
00913 
00914   a = recog->adin;
00915   if (a->speechlen + len > MAXSPEECHLEN) {
00916     /* just mark as overflowed, and continue this thread */
00917     pthread_mutex_lock(&(a->mutex));
00918     a->adinthread_buffer_overflowed = TRUE;
00919     pthread_mutex_unlock(&(a->mutex));
00920     return(0);
00921   }
00922   pthread_mutex_lock(&(a->mutex));
00923   memcpy(&(a->speech[a->speechlen]), now, len * sizeof(SP16));
00924   a->speechlen += len;
00925   pthread_mutex_unlock(&(a->mutex));
00926 #ifdef THREAD_DEBUG
00927   jlog("DEBUG: input: stored %d samples, total=%d\n", len, a->speechlen);
00928 #endif
00929 
00930   return(0);                    /* continue */
00931 }
00932 
00943 static void
00944 adin_thread_input_main(void *dummy)
00945 {
00946   Recog *recog;
00947   int ret;
00948 
00949   recog = dummy;
00950 
00951   ret = adin_cut(adin_store_buffer, NULL, recog);
00952 
00953   if (ret == -2) {              /* termination request by ad_check? */
00954     jlog("Error: adin thread exit with termination request by checker\n");
00955   } else if (ret == -1) {       /* error */
00956     jlog("Error: adin thread exit with error\n");
00957   } else if (ret == 0) {        /* EOF */
00958     jlog("Stat: adin thread end with EOF\n");
00959   }
00960   recog->adin->adinthread_ended = TRUE;
00961 
00962   /* return to end this thread */
00963 }
00964 
00977 boolean
00978 adin_thread_create(Recog *recog)
00979 {
00980   ADIn *a;
00981 
00982   a = recog->adin;
00983 
00984   /* init storing buffer */
00985   a->speech = (SP16 *)mymalloc(sizeof(SP16) * MAXSPEECHLEN);
00986   a->speechlen = 0;
00987 
00988   a->transfer_online = FALSE; /* tell adin-mic thread to wait at initial */
00989   a->adinthread_buffer_overflowed = FALSE;
00990   a->adinthread_ended = FALSE;
00991 
00992   if (pthread_mutex_init(&(a->mutex), NULL) != 0) { /* error */
00993     jlog("ERROR: adin_thread_create: failed to initialize mutex\n");
00994     return FALSE;
00995   }
00996   if (pthread_create(&(recog->adin->adin_thread), NULL, (void *)adin_thread_input_main, recog) != 0) {
00997     jlog("ERROR: adin_thread_create: failed to create AD-in thread\n");
00998     return FALSE;
00999   }
01000   if (pthread_detach(recog->adin->adin_thread) != 0) { /* not join, run forever */
01001     jlog("ERROR: adin_thread_create: failed to detach AD-in thread\n");
01002     return FALSE;
01003   }
01004   jlog("STAT: AD-in thread created\n");
01005   return TRUE;
01006 }
01007 
01020 boolean
01021 adin_thread_cancel(Recog *recog)
01022 {
01023   ADIn *a;
01024   int ret;
01025 
01026   if (recog->adin->adinthread_ended) return TRUE;
01027 
01028   /* send a cencellation request to the A/D-in thread */
01029   ret = pthread_cancel(recog->adin->adin_thread);
01030   if (ret != 0) {
01031     if (ret == ESRCH) {
01032       jlog("STAT: adin_thread_cancel: no A/D-in thread\n");
01033       recog->adin->adinthread_ended = TRUE;
01034       return TRUE;
01035     } else {
01036       jlog("Error: adin_thread_cancel: failed to cancel A/D-in thread\n");
01037       return FALSE;
01038     }
01039   }
01040   /* wait for the thread to terminate */
01041   ret = pthread_join(recog->adin->adin_thread, NULL);
01042   if (ret != 0) {
01043     if (ret == EINVAL) {
01044       jlog("InternalError: adin_thread_cancel: AD-in thread is invalid\n");
01045       recog->adin->adinthread_ended = TRUE;
01046       return FALSE;
01047     } else if (ret == ESRCH) {
01048       jlog("STAT: adin_thread_cancel: no A/D-in thread\n");
01049       recog->adin->adinthread_ended = TRUE;
01050       return TRUE;
01051     } else if (ret == EDEADLK) {
01052       jlog("InternalError: adin_thread_cancel: dead lock or self thread?\n");
01053       recog->adin->adinthread_ended = TRUE;
01054       return FALSE;
01055     } else {
01056       jlog("Error: adin_thread_cancel: failed to wait end of A/D-in thread\n");
01057       return FALSE;
01058     }
01059   }
01060 
01061   jlog("STAT: AD-in thread deleted\n");
01062   recog->adin->adinthread_ended = TRUE;
01063   return TRUE;
01064 }
01065 
01066 /****************************/
01067 /* process thread functions */
01068 /****************************/
01069 
01094 static int
01095 adin_thread_process(int (*ad_process)(SP16 *, int, Recog *), int (*ad_check)(Recog *), Recog *recog)
01096 {
01097   int prev_len, nowlen;
01098   int ad_process_ret;
01099   int i;
01100   boolean overflowed_p;
01101   boolean transfer_online_local;
01102   boolean ended_p;
01103   ADIn *a;
01104 
01105   a = recog->adin;
01106 
01107   /* reset storing buffer --- input while recognition will be ignored */
01108   pthread_mutex_lock(&(a->mutex));
01109   /*if (speechlen == 0) transfer_online = TRUE;*/ /* tell adin-mic thread to start recording */
01110   a->transfer_online = TRUE;
01111 #ifdef THREAD_DEBUG
01112   jlog("DEBUG: process: reset, speechlen = %d, online=%d\n", a->speechlen, a->transfer_online);
01113 #endif
01114   a->adinthread_buffer_overflowed = FALSE;
01115   pthread_mutex_unlock(&(a->mutex));
01116 
01117   /* main processing loop */
01118   prev_len = 0;
01119   for(;;) {
01120     /* get current length (locking) */
01121     pthread_mutex_lock(&(a->mutex));
01122     nowlen = a->speechlen;
01123     overflowed_p = a->adinthread_buffer_overflowed;
01124     transfer_online_local = a->transfer_online;
01125     ended_p = a->adinthread_ended;
01126     pthread_mutex_unlock(&(a->mutex));
01127     /* check if thread is alive */
01128     if (ended_p) {
01129       /* adin thread has already exited, so return EOF to stop this input */
01130       return(0);
01131     }
01132     /* check if other input thread has overflowed */
01133     if (overflowed_p) {
01134       jlog("WARNING: adin_thread_process: too long input (> %d samples), segmented now\n", MAXSPEECHLEN);
01135       /* segment input here */
01136       pthread_mutex_lock(&(a->mutex));
01137       a->speechlen = 0;
01138       a->transfer_online = transfer_online_local = FALSE;
01139       pthread_mutex_unlock(&(a->mutex));
01140       return(1);                /* return with segmented status */
01141     }
01142     /* callback poll */
01143     if (ad_check != NULL) {
01144       if ((i = (*(ad_check))(recog)) < 0) {
01145         if ((i == -1 && nowlen == 0) || i == -2) {
01146           pthread_mutex_lock(&(a->mutex));
01147           a->transfer_online = transfer_online_local = FALSE;
01148           a->speechlen = 0;
01149           pthread_mutex_unlock(&(a->mutex));
01150           return(-2);
01151         }
01152       }
01153     }
01154     if (prev_len < nowlen) {
01155 #ifdef THREAD_DEBUG
01156       jlog("DEBUG: process: proceed [%d-%d]\n",prev_len, nowlen);
01157 #endif
01158       /* got new sample, process */
01159       /* As the speech[] buffer is monotonously increase,
01160          content of speech buffer [prev_len..nowlen] would not alter
01161          in both threads
01162          So locking is not needed while processing.
01163        */
01164       /*jlog("DEBUG: main: read %d-%d\n", prev_len, nowlen);*/
01165       if (ad_process != NULL) {
01166         ad_process_ret = (*ad_process)(&(a->speech[prev_len]), nowlen - prev_len, recog);
01167 #ifdef THREAD_DEBUG
01168         jlog("DEBUG: ad_process_ret=%d\n", ad_process_ret);
01169 #endif
01170         switch(ad_process_ret) {
01171         case 1:                 /* segmented */
01172           /* segmented by callback function */
01173           /* purge processed samples and keep transfering */
01174           pthread_mutex_lock(&(a->mutex));
01175           if(a->speechlen > nowlen) {
01176             memmove(a->speech, &(a->speech[nowlen]), (a->speechlen - nowlen) * sizeof(SP16));
01177             a->speechlen -= nowlen;
01178           } else {
01179             a->speechlen = 0;
01180           }
01181           a->transfer_online = transfer_online_local = FALSE;
01182           pthread_mutex_unlock(&(a->mutex));
01183           /* keep transfering */
01184           return(2);            /* return with segmented status */
01185         case -1:                /* error */
01186           pthread_mutex_lock(&(a->mutex));
01187           a->transfer_online = transfer_online_local = FALSE;
01188           pthread_mutex_unlock(&(a->mutex));
01189           return(-1);           /* return with error */
01190         }
01191       }
01192       if (a->rehash) {
01193         /* rehash */
01194         pthread_mutex_lock(&(a->mutex));
01195         if (debug2_flag) jlog("STAT: adin_cut: rehash from %d to %d\n", a->speechlen, a->speechlen - prev_len);
01196         a->speechlen -= prev_len;
01197         nowlen -= prev_len;
01198         memmove(a->speech, &(a->speech[prev_len]), a->speechlen * sizeof(SP16));
01199         pthread_mutex_unlock(&(a->mutex));
01200         a->rehash = FALSE;
01201       }
01202       prev_len = nowlen;
01203     } else {
01204       if (transfer_online_local == FALSE) {
01205         /* segmented by zero-cross */
01206         /* reset storing buffer for next input */
01207         pthread_mutex_lock(&(a->mutex));
01208         a->speechlen = 0;
01209         pthread_mutex_unlock(&(a->mutex));
01210         break;
01211       }
01212       usleep(50000);   /* wait = 0.05sec*/            
01213     }
01214   }
01215 
01216   /* as threading assumes infinite input */
01217   /* return value should be 1 (segmented) */
01218   return(1);
01219 }
01220 #endif /* HAVE_PTHREAD */
01221 
01222 
01223 
01224 
01258 int
01259 adin_go(int (*ad_process)(SP16 *, int, Recog *), int (*ad_check)(Recog *), Recog *recog)
01260 {
01261   /* output listening start message */
01262   callback_exec(CALLBACK_EVENT_SPEECH_READY, recog);
01263 #ifdef HAVE_PTHREAD
01264   if (recog->adin->enable_thread) {
01265     return(adin_thread_process(ad_process, ad_check, recog));
01266   }
01267 #endif
01268   return(adin_cut(ad_process, ad_check, recog));
01269 }
01270 
01289 boolean
01290 adin_standby(ADIn *a, int freq, void *arg)
01291 {
01292   if (a->need_zmean) zmean_reset();
01293   if (a->ad_standby != NULL) return(a->ad_standby(freq, arg));
01294   return TRUE;
01295 }
01313 boolean
01314 adin_begin(ADIn *a, char *file_or_dev_name)
01315 {
01316   if (debug2_flag && a->input_side_segment) jlog("Stat: adin_begin: skip\n");
01317   if (a->input_side_segment == FALSE) {
01318     a->total_captured_len = 0;
01319     if (a->need_zmean) zmean_reset();
01320     if (a->ad_begin != NULL) return(a->ad_begin(file_or_dev_name));
01321   }
01322   return TRUE;
01323 }
01339 boolean
01340 adin_end(ADIn *a)
01341 {
01342   if (debug2_flag && a->input_side_segment) jlog("Stat: adin_end: skip\n");
01343   if (a->input_side_segment == FALSE) {
01344     if (a->ad_end != NULL) return(a->ad_end());
01345   }
01346   return TRUE;
01347 }
01348 
01363 void
01364 adin_free_param(Recog *recog)
01365 {
01366   ADIn *a;
01367 
01368   a = recog->adin;
01369 
01370   if (a->ds) {
01371     ds48to16_free(a->ds);
01372     a->ds = NULL;
01373   }
01374   if (a->adin_cut_on) {
01375     free_count_zc_e(&(a->zc));
01376   }
01377   if (a->down_sample) {
01378     free(a->buffer48);
01379   }
01380   free(a->swapbuf);
01381   free(a->cbuf);
01382   free(a->buffer);
01383 #ifdef HAVE_PTHREAD
01384   if (a->speech) free(a->speech);
01385 #endif
01386 }
01387 
01388 /* end of file */