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