void desa2_freeswitch_double(double *input, double *mean1, double *mean2, double *var1, double *var2) { int i; circ_buffer_t b; sma_buffer_t sma_b; sma_buffer_t sqa_b; double freq[BLOCK]; // frequency estimates INIT_CIRC_BUFFER(&b, BLOCK); INIT_SMA_BUFFER(&sma_b, 10); INIT_SMA_BUFFER(&sqa_b, 10); INSERT_DOUBLE_FRAME(&b, input, BLOCK); // calculate the frequency estimate for each sample as in FS for (i = 0; i < (BLOCK - P); i++) { freq[i] = desa2_fs(&b, i); APPEND_SMA_VAL(&sma_b, freq[i]); APPEND_SMA_VAL(&sqa_b, freq[i] * freq[i]); *var1 = sqa_b.sma - (sma_b.sma * sma_b.sma); printf("<<< AVMD v[%f] f[%f][%f]Hz sma[%f][%f]Hz sqa[%f]\tsample[%d]\t[%f][%f]>>>\n", *var1, freq[i], TO_HZ(8000, freq[i]), sma_b.sma, TO_HZ(8000, sma_b.sma), sqa_b.sma, i, input[i], GET_SAMPLE((&b), i)); } /* set mean */ *mean1 = sma_b.sma; /* calculate the variance */ *var1 = sqa_b.sma - (sma_b.sma * sma_b.sma); /* for comparison calculate mean2 frequency & var2 */ double mean = 0.0; for (i = 0; i < (BLOCK - P); i++) { mean += freq[i]; } mean /= (double) (BLOCK - P); *mean2 = mean; *var2 = 0.0; for (i = 0; i < (BLOCK - P); i++ ) { *var2 += freq[i] * freq[i]; } *var2 /= (double)(BLOCK - P); *var2 -= (mean * mean); free(b.buf); free(sma_b.data); free(sqa_b.data); return; }
/*! \brief Process and convert data to be used by the find_beep() function * * @author Eric des Courtis * @param vmd_info The session information associated with the call. * @param frame The audio data. * @return The success or failure of the function. */ static switch_bool_t process_data(vmd_session_info_t *vmd_info, switch_frame_t *frame) { uint32_t i; unsigned int j; double pts[P]; int16_t *data; int16_t max; //len = frame->samples * sizeof(int16_t); data = (int16_t *) frame->data; for (max = (int16_t) abs(data[0]), i = 1; i < frame->samples; i++) { if ((int16_t) abs(data[i]) > max) { max = (int16_t) abs(data[i]); } } /* if (vmd_info->data_len != len){ vmd_info->data_len = len; if (vmd_info->data != NULL) free(vmd_info->data); vmd_info->data = (int16_t *)malloc(len); if (vmd_info->data == NULL) return SWITCH_FALSE; } (void)memcpy(vmd_info->data, data, len); for(i = 2; i < frame->samples; i++){ vmd_info->data[i] = 0.0947997 * data[i] - 0.0947997 * data[i - 2] - 1.4083405 * vmd_info->data[i - 1] + 0.8104005 * vmd_info->data[i - 2]; } */ for (i = 0, j = vmd_info->pos; i < frame->samples; j++, j %= POINTS, i += 5) { /* convert_pts(vmd_info->data + i, pts); */ convert_pts(data + i, pts, max); vmd_info->points[j].freq = TO_HZ(freq_estimator(pts)); vmd_info->points[j].ampl = ampl_estimator(pts); vmd_info->pos = j % POINTS; find_beep(vmd_info, frame); } return SWITCH_TRUE; }
/*! \brief Process one frame of data with avmd algorithm * @author Eric des Courtis * @param session An avmd session * @param frame A audio frame */ static void avmd_process(avmd_session_t *session, switch_frame_t *frame) { switch_event_t *event; switch_status_t status; switch_event_t *event_copy; switch_channel_t *channel; circ_buffer_t *b; size_t pos; double f; double a; double error = 0.0; double success = 0.0; double amp = 0.0; double s_rate; double e_rate; double avg_a; double sine_len; uint32_t sine_len_i; int valid; b = &session->b; /*! If beep has already been detected skip the CPU heavy stuff */ if(session->state.beep_state == BEEP_DETECTED){ return; } /*! Precompute values used heavily in the inner loop */ sine_len_i = SINE_LEN(session->rate); sine_len = (double)sine_len_i; channel = switch_core_session_get_channel(session->session); /*! Insert frame of 16 bit samples into buffer */ INSERT_INT16_FRAME(b, (int16_t *)(frame->data), frame->samples); /*! INNER LOOP -- OPTIMIZATION TARGET */ for(pos = GET_BACKLOG_POS(b); pos != (GET_CURRENT_POS(b) - P); pos++){ /*! Get a desa2 frequency estimate in Hertz */ f = TO_HZ(session->rate, desa2(b, pos)); /*! Don't caculate amplitude if frequency is not within range */ if(f < MIN_FREQUENCY || f > MAX_FREQUENCY) { a = 0.0; error += 1.0; } else { a = amplitude(b, pos, f); success += 1.0; if(!ISNAN(a)){ amp += a; } } /*! Every once in a while we evaluate the desa2 and amplitude results */ if(((pos + 1) % sine_len_i) == 0){ s_rate = success / (error + success); e_rate = error / (error + success); avg_a = amp / sine_len; /*! Results out of these ranges are considered invalid */ valid = 0; if( s_rate > 0.60 && avg_a > 0.50) valid = 1; else if(s_rate > 0.65 && avg_a > 0.45) valid = 1; else if(s_rate > 0.70 && avg_a > 0.40) valid = 1; else if(s_rate > 0.80 && avg_a > 0.30) valid = 1; else if(s_rate > 0.95 && avg_a > 0.05) valid = 1; else if(s_rate >= 0.99 && avg_a > 0.04) valid = 1; else if(s_rate == 1.00 && avg_a > 0.02) valid = 1; if(valid) { APPEND_SMA_VAL(&session->sma_b, s_rate * avg_a); } else { APPEND_SMA_VAL(&session->sma_b, 0.0 ); } /*! If sma is higher then 0 we have some kind of detection (increase this value to eliminate false positives ex: 0.01) */ if(session->sma_b.sma > 0.00){ /*! Throw an event to FreeSWITCH */ status = switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, AVMD_EVENT_BEEP); if(status != SWITCH_STATUS_SUCCESS) { return; } switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Beep-Status", "stop"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Unique-ID", switch_core_session_get_uuid(session->session)); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-command", "avmd"); if ((switch_event_dup(&event_copy, event)) != SWITCH_STATUS_SUCCESS) { return; } switch_core_session_queue_event(session->session, &event); switch_event_fire(&event_copy); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session->session), SWITCH_LOG_INFO, "<<< AVMD - Beep Detected >>>\n"); switch_channel_set_variable(channel, "avmd_detect", "TRUE"); RESET_SMA_BUFFER(&session->sma_b); session->state.beep_state = BEEP_DETECTED; return; } amp = 0.0; success = 0.0; error = 0.0; } } }