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

Juliusに対してThu Jul 23 12:16:22 2009に生成されました。  doxygen 1.5.1