📄 adin-cut.c
字号:
/* initialize buffers */ /**********************/ if (buffer == NULL) { /* beginning of stream */ buffer = (SP16 *)mymalloc(sizeof(SP16) * MAXSPEECHLEN); cbuf = (SP16 *)mymalloc(sizeof(SP16) * c_length); swapbuf = (SP16 *)mymalloc(sizeof(SP16) * sbsize); } if (need_init) { bpmax = MAXSPEECHLEN; bp = 0; is_valid_data = FALSE; /* reset zero-cross status */ if (adin_cut_on) { init_count_zc_e(thres, c_length, c_offset); } end_of_stream = FALSE; nc = 0; sblen = 0; need_init = FALSE; /* for next call */ } /****************/ /* resume input */ /****************/ /* restart speech input if paused on the last call */ if (ad_resume != NULL) { if ((*ad_resume)() == FALSE) return(-1); } /*************/ /* main loop */ /*************/ for (;;) { /****************************/ /* read in new speech input */ /****************************/ if (end_of_stream) { /* already reaches end of stream, just process the rest */ current_len = bp; } else { /*****************************************************/ /* get samples from input device to temporary buffer */ /*****************************************************/ /* buffer[0..bp] is the current remaining samples */ /* mic input - samples exist in a device buffer tcpip input - samples exist in a socket file input - samples in a file Return value is the number of read samples. If no data exists in the device (in case of mic input), ad_read() will return 0. If reached end of stream (in case end of file or receive end ack from tcpip client), it will return -1. If error, returns -2. */ cnt = (*ad_read)(&(buffer[bp]), bpmax - bp); if (cnt < 0) { /* end of stream or error */ /* set the end status */ if (cnt == -2) end_status = -1; /* end by error */ else if (cnt == -1) end_status = 0; /* end by normal end of stream */ /* now the input has been ended, we should not get further speech input in the next loop, instead just process the samples in the temporary buffer until the entire data is processed. */ end_of_stream = TRUE; cnt = 0; /* no new input */ /* in case the first trial of ad_read() fails, exit this loop */ if (bp == 0) break; } /*************************************************/ /* some speech processing for the incoming input */ /*************************************************/ if (cnt > 0) { if (strip_flag) { /* strip off successive zero samples */ len = strip_zero(&(buffer[bp]), cnt); if (len != cnt) cnt = len; } if (need_zmean) { /* remove DC offset */ sub_zmean(&(buffer[bp]), cnt); } } /* current len = current samples in buffer */ current_len = bp + cnt; }#ifdef THREAD_DEBUG if (end_of_stream) { printf("stream already ended\n"); } printf("input: get %d samples [%d-%d]\n", current_len - bp, bp, current_len);#endif /**************************************************/ /* call the periodic callback (non threaded mode) */ /*************************************************/ /* this function is mainly for periodic checking of incoming command in module mode */ /* in threaded mode, this will be done in process thread, not here in adin thread */ if (ad_check != NULL#ifdef HAVE_PTHREAD && !enable_thread#endif ) { /* if ad_check() returns value < 0, termination of speech input is required */ if ((i = (*ad_check)()) < 0) { /* -1: soft termination -2: hard termination */ // if ((i == -1 && current_len == 0) || i == -2) { if (i == -2 || (i == -1 && adin_cut_on && is_valid_data == FALSE) || (i == -1 && !adin_cut_on && current_len == 0)) { end_status = -2; /* recognition terminated by outer function */ goto break_input; } } } /***********************************************************************/ /* if no data has got but not end of stream, repeat next input samples */ /***********************************************************************/ if (current_len == 0) continue; /* When not adin_cut mode, all incoming data is valid. So is_valid_data should be set to TRUE when some input first comes till this input ends. So, if some data comes, set is_valid_data to TRUE here. */ if (!adin_cut_on && is_valid_data == FALSE && current_len > 0) { is_valid_data = TRUE; } /******************************************************/ /* prepare for processing samples in temporary buffer */ /******************************************************/ wstep = DEFAULT_WSTEP; /* process unit (should be smaller than cycle buffer) */ /* imax: total length that should be processed at one ad_read() call */ /* if in real-time mode and not threaded, recognition process will be called and executed as the ad_process() callback within this function. If the recognition speed is over the real time, processing all the input samples at the loop below may result in the significant delay of getting next input, that may result in the buffer overflow of the device (namely a microphone device will suffer from this). So, in non-threaded mode, in order to avoid buffer overflow and input frame dropping, we will leave here by processing only one segment [0..wstep], and leave the rest in the temporary buffer. */#ifdef HAVE_PTHREAD if (enable_thread) imax = current_len; /* process whole */ else imax = (current_len < wstep) ? current_len : wstep; /* one step */#else imax = (current_len < wstep) ? current_len : wstep; /* one step */#endif /* wstep: unit length for the loop below */ if (wstep > current_len) wstep = current_len;#ifdef THREAD_DEBUG printf("process %d samples by %d step\n", imax, wstep);#endif#ifdef HAVE_PTHREAD if (enable_thread) { /* get transfer status to local */ pthread_mutex_lock(&mutex); transfer_online_local = transfer_online; pthread_mutex_unlock(&mutex); }#endif /*********************************************************/ /* start processing buffer[0..current_len] by wstep step */ /*********************************************************/ i = 0; while (i + wstep <= imax) { if (adin_cut_on) { /********************/ /* check triggering */ /********************/ /* the cycle buffer in count_zc_e() holds the last samples of (head_margin) miliseconds, and the zerocross over the threshold level are counted within the cycle buffer */ /* store the new data to cycle buffer and update the count */ /* return zero-cross num in the cycle buffer */ zc = count_zc_e(&(buffer[i]), wstep); if (zc > noise_zerocross) { /* now triggering */ if (is_valid_data == FALSE) { /*****************************************************/ /* process off, trigger on: detect speech triggering */ /*****************************************************/ is_valid_data = TRUE; /* start processing */ nc = 0;#ifdef THREAD_DEBUG printf("detect on\n");#endif /****************************************/ /* flush samples stored in cycle buffer */ /****************************************/ /* (last (head_margin) msec samples */ /* if threaded mode, processing means storing them to speech[]. if ignore_speech_while_recog is on (default), ignore the data if transfer is offline (=while processing second pass). Else, datas are stored even if transfer is offline */ if ( ad_process != NULL#ifdef HAVE_PTHREAD && (!enable_thread || !ignore_speech_while_recog || transfer_online_local)#endif ) { /* copy content of cycle buffer to cbuf */ zc_copy_buffer(cbuf, &len); /* Note that the last 'wstep' samples are the same as the current samples 'buffer[i..i+wstep]', and they will be processed later. So, here only the samples cbuf[0...len-wstep] will be processed */ if (len - wstep > 0) {#ifdef THREAD_DEBUG printf("callback for buffered samples (%d bytes)\n", len - wstep);#endif ad_process_ret = (*ad_process)(cbuf, len - wstep); switch(ad_process_ret) { case 1: /* segmentation notification from process callback */#ifdef HAVE_PTHREAD if (enable_thread) { /* in threaded mode, just stop transfer */ pthread_mutex_lock(&mutex); transfer_online = transfer_online_local = FALSE; pthread_mutex_unlock(&mutex); } else { /* in non-threaded mode, set end status and exit loop */ end_status = 1; adin_purge(i); goto break_input; } break;#else /* in non-threaded mode, set end status and exit loop */ end_status = 1; adin_purge(i); goto break_input;#endif case -1: /* error occured in callback */ /* set end status and exit loop */ end_status = -1; goto break_input; } } } } else { /* is_valid_data == TRUE */ /******************************************************/ /* process on, trigger on: we are in a speech segment */ /******************************************************/ if (nc > 0) { /*************************************/ /* re-triggering in trailing silence */ /*************************************/ #ifdef THREAD_DEBUG printf("re-triggered\n");#endif /* reset noise counter */ nc = 0;#ifdef TMP_FIX_200602 if (ad_process != NULL#ifdef HAVE_PTHREAD && (!enable_thread || !ignore_speech_while_recog || transfer_online_local)#endif ) {#endif /*************************************************/ /* process swap buffer stored while tail silence */ /*************************************************/ /* In trailing silence, the samples within the tail margin length will be processed immediately, but samples after the tail margin will not be processed, instead stored in swapbuf[]. If re-triggering occurs while in the trailing silence, the swapped samples should be processed now to catch up with current input */ if (sblen > 0) {#ifdef THREAD_DEBUG printf("callback for swapped %d samples\n", sblen);#endif ad_process_ret = (*ad_process)(swapbuf, sblen); sblen = 0; switch(ad_process_ret) { case 1: /* segmentation notification from process callback */#ifdef HAVE_PTHREAD if (enable_thread) { /* in threaded mode, just stop transfer */ pthread_mutex_lock(&mutex); transfer_online = transfer_online_local = FALSE; pthread_mutex_unlock(&mutex); } else { /* in non-threaded mode, set end status and exit loop */ end_status = 1; adin_purge(i); goto break_input; } break;#else /* in non-threaded mode, set end status and exit loop */ end_status = 1; adin_purge(i); goto break_input;#endif case -1: /* error occured in callback */ /* set end status and exit loop */ end_status = -1; goto break_input; } }#ifdef TMP_FIX_200602 }#endif } } } else if (is_valid_data == TRUE) { /*******************************************************/ /* process on, trigger off: processing tailing silence */ /*******************************************************/ #ifdef THREAD_DEBUG printf("TRAILING SILENCE\n");#endif if (nc == 0) { /* start of tail silence: prepare valiables for start swapbuf[] */ rest_tail = sbsize - c_length; sblen = 0;#ifdef THREAD_DEBUG printf("start tail silence, rest_tail = %d\n", rest_tail);#endif } /* increment noise counter */ nc++; } } /* end of triggering handlers */ /********************************************************************/ /* process the current segment buffer[i...i+wstep] if process == on */ /********************************************************************/ if (adin_cut_on && is_valid_data && nc > 0 && rest_tail == 0) { /* The current trailing silence is now longer than the user- specified tail margin length, so the current samples should not be processed now. But if 're-triggering' occurs in the trailing silence later, they should be processed then. So we just store the overed samples in swapbuf[] and not process them now */ #ifdef THREAD_DEBUG printf("tail silence over, store to swap buffer (nc=%d, rest_tail=%d, sblen=%d-%d)\n", nc, rest_tail, sblen, sblen+wstep);#endif if (sblen + wstep > sbsize) { j_printerr("Error: swapbuf exceeded!\n"); } memcpy(&(swapbuf[sblen]), &(buffer[i]), wstep * sizeof(SP16)); sblen += wstep; } else { /* we are in a normal speech segment (nc == 0), or
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -