libjulius/src/adin-cut.c

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

Generated on Tue Dec 18 15:59:50 2007 for Julius by  doxygen 1.5.4