Julius 4.2
|
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 */