From 2f3fa066545f84fad3dd544a8f736e2cd85198e5 Mon Sep 17 00:00:00 2001 From: Dmytro Bogovych Date: Mon, 25 Mar 2019 21:02:59 +0200 Subject: [PATCH] - avoid extra dependency on boost --- src/engine/audio/Audio_Mixer.cpp | 2 +- src/engine/media/MT_Dtmf.cpp | 1106 ++++++++++++++--------------- src/engine/media/MT_SevanaMos.cpp | 12 +- 3 files changed, 562 insertions(+), 558 deletions(-) diff --git a/src/engine/audio/Audio_Mixer.cpp b/src/engine/audio/Audio_Mixer.cpp index 3026ea38..5e4aca7c 100644 --- a/src/engine/audio/Audio_Mixer.cpp +++ b/src/engine/audio/Audio_Mixer.cpp @@ -22,7 +22,7 @@ Mixer::Stream::Stream() mResampler32.start(AUDIO_CHANNELS, 32000, AUDIO_SAMPLERATE); mResampler48.start(AUDIO_CHANNELS, 48000, AUDIO_SAMPLERATE); mActive = false; - mContext = NULL; + mContext = nullptr; mSSRC = 0; mFadeOutCounter = 0; mData.setCapacity(AUDIO_SPK_BUFFER_SIZE * AUDIO_SPK_BUFFER_COUNT); diff --git a/src/engine/media/MT_Dtmf.cpp b/src/engine/media/MT_Dtmf.cpp index 7bc2bc53..6fee22ab 100644 --- a/src/engine/media/MT_Dtmf.cpp +++ b/src/engine/media/MT_Dtmf.cpp @@ -53,7 +53,7 @@ void DtmfBuilder::buildRfc2833(int tone, int duration, int volume, bool endOfEve #ifndef TARGET_WIN # include # if !defined(TARGET_ANDROID) && !defined(TARGET_WIN) -# include +//# include # endif #endif @@ -330,560 +330,560 @@ bool DtmfContext::getRfc2833(int milliseconds, ByteBuffer& output, ByteBuffer& s return true; } -typedef struct -{ - float v2; - float v3; - float fac; -} goertzel_state_t; - -#define MAX_DTMF_DIGITS 128 - -typedef struct -{ - int hit1; - int hit2; - int hit3; - int hit4; - int mhit; - - goertzel_state_t row_out[4]; - goertzel_state_t col_out[4]; - goertzel_state_t row_out2nd[4]; - goertzel_state_t col_out2nd[4]; - goertzel_state_t fax_tone; - goertzel_state_t fax_tone2nd; - float energy; - - int current_sample; - char digits[MAX_DTMF_DIGITS + 1]; - int current_digits; - int detected_digits; - int lost_digits; - int digit_hits[16]; - int fax_hits; -} dtmf_detect_state_t; - -typedef struct -{ - float fac; -} tone_detection_descriptor_t; - -void zap_goertzel_update(goertzel_state_t *s, int16_t x[], int samples); -float zap_goertzel_result (goertzel_state_t *s); -void zap_dtmf_detect_init(dtmf_detect_state_t *s); -int zap_dtmf_detect(dtmf_detect_state_t *s, int16_t amp[], int samples, int isradio); -int zap_dtmf_get(dtmf_detect_state_t *s, char *buf, int max); - -DTMFDetector::DTMFDetector() -:mState(NULL) -{ - mState = malloc(sizeof(dtmf_detect_state_t)); - - memset(mState, 0, sizeof(dtmf_detect_state_t)); - zap_dtmf_detect_init((dtmf_detect_state_t*)mState); -} - -DTMFDetector::~DTMFDetector() -{ - if (mState) - free(mState); -} - -std::string DTMFDetector::streamPut(unsigned char* samples, unsigned int size) -{ - char buf[16]; buf[0] = 0; - if (zap_dtmf_detect((dtmf_detect_state_t*)mState, (int16_t*)samples, size/2, 0)) - zap_dtmf_get((dtmf_detect_state_t*)mState, buf, 15); - return buf; +typedef struct +{ + float v2; + float v3; + float fac; +} goertzel_state_t; + +#define MAX_DTMF_DIGITS 128 + +typedef struct +{ + int hit1; + int hit2; + int hit3; + int hit4; + int mhit; + + goertzel_state_t row_out[4]; + goertzel_state_t col_out[4]; + goertzel_state_t row_out2nd[4]; + goertzel_state_t col_out2nd[4]; + goertzel_state_t fax_tone; + goertzel_state_t fax_tone2nd; + float energy; + + int current_sample; + char digits[MAX_DTMF_DIGITS + 1]; + int current_digits; + int detected_digits; + int lost_digits; + int digit_hits[16]; + int fax_hits; +} dtmf_detect_state_t; + +typedef struct +{ + float fac; +} tone_detection_descriptor_t; + +void zap_goertzel_update(goertzel_state_t *s, int16_t x[], int samples); +float zap_goertzel_result (goertzel_state_t *s); +void zap_dtmf_detect_init(dtmf_detect_state_t *s); +int zap_dtmf_detect(dtmf_detect_state_t *s, int16_t amp[], int samples, int isradio); +int zap_dtmf_get(dtmf_detect_state_t *s, char *buf, int max); + +DTMFDetector::DTMFDetector() +:mState(NULL) +{ + mState = malloc(sizeof(dtmf_detect_state_t)); + + memset(mState, 0, sizeof(dtmf_detect_state_t)); + zap_dtmf_detect_init((dtmf_detect_state_t*)mState); +} + +DTMFDetector::~DTMFDetector() +{ + if (mState) + free(mState); +} + +std::string DTMFDetector::streamPut(unsigned char* samples, unsigned int size) +{ + char buf[16]; buf[0] = 0; + if (zap_dtmf_detect((dtmf_detect_state_t*)mState, (int16_t*)samples, size/2, 0)) + zap_dtmf_get((dtmf_detect_state_t*)mState, buf, 15); + return buf; } void DTMFDetector::resetState() { zap_dtmf_detect_init((dtmf_detect_state_t*)mState); -} - -#ifndef TRUE - -# define FALSE 0 -# define TRUE (!FALSE) - -#endif - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -//#define USE_3DNOW - -/* Basic DTMF specs: - * - * Minimum tone on = 40ms - * Minimum tone off = 50ms - * Maximum digit rate = 10 per second - * Normal twist <= 8dB accepted - * Reverse twist <= 4dB accepted - * S/N >= 15dB will detect OK - * Attenuation <= 26dB will detect OK - * Frequency tolerance +- 1.5% will detect, +-3.5% will reject - */ - -#define SAMPLE_RATE 8000.0 - -#define DTMF_THRESHOLD 8.0e7 -#define FAX_THRESHOLD 8.0e7 -#define FAX_2ND_HARMONIC 2.0 /* 4dB */ -#define DTMF_NORMAL_TWIST 6.3 /* 8dB */ -#define DTMF_REVERSE_TWIST ((isradio) ? 4.0 : 2.5) /* 4dB normal */ -#define DTMF_RELATIVE_PEAK_ROW 6.3 /* 8dB */ -#define DTMF_RELATIVE_PEAK_COL 6.3 /* 8dB */ -#define DTMF_2ND_HARMONIC_ROW ((isradio) ? 1.7 : 2.5) /* 4dB normal */ -#define DTMF_2ND_HARMONIC_COL 63.1 /* 18dB */ - -static tone_detection_descriptor_t dtmf_detect_row[4]; -static tone_detection_descriptor_t dtmf_detect_col[4]; -static tone_detection_descriptor_t dtmf_detect_row_2nd[4]; -static tone_detection_descriptor_t dtmf_detect_col_2nd[4]; -static tone_detection_descriptor_t fax_detect; -static tone_detection_descriptor_t fax_detect_2nd; - -static float dtmf_row[] = -{ - 697.0, 770.0, 852.0, 941.0 -}; -static float dtmf_col[] = -{ - 1209.0, 1336.0, 1477.0, 1633.0 -}; - -static float fax_freq = 1100.0; - -static char dtmf_positions[] = "123A" "456B" "789C" "*0#D"; - -static void goertzel_init(goertzel_state_t *s, - tone_detection_descriptor_t *t) -{ - s->v2 = - s->v3 = 0.0; - s->fac = t->fac; -} -/*- End of function --------------------------------------------------------*/ - -#if defined(USE_3DNOW) -static inline void _dtmf_goertzel_update(goertzel_state_t *s, - float x[], - int samples) -{ - int n; - float v; - int i; - float vv[16]; - - vv[4] = s[0].v2; - vv[5] = s[1].v2; - vv[6] = s[2].v2; - vv[7] = s[3].v2; - vv[8] = s[0].v3; - vv[9] = s[1].v3; - vv[10] = s[2].v3; - vv[11] = s[3].v3; - vv[12] = s[0].fac; - vv[13] = s[1].fac; - vv[14] = s[2].fac; - vv[15] = s[3].fac; - - //v1 = s->v2; - //s->v2 = s->v3; - //s->v3 = s->fac*s->v2 - v1 + x[0]; - - __asm__ __volatile__ ( - " femms;\n" - - " movq 16(%%edx),%%mm2;\n" - " movq 24(%%edx),%%mm3;\n" - " movq 32(%%edx),%%mm4;\n" - " movq 40(%%edx),%%mm5;\n" - " movq 48(%%edx),%%mm6;\n" - " movq 56(%%edx),%%mm7;\n" - - " jmp 1f;\n" - " .align 32;\n" - - " 1: ;\n" - " prefetch (%%eax);\n" - " movq %%mm3,%%mm1;\n" - " movq %%mm2,%%mm0;\n" - " movq %%mm5,%%mm3;\n" - " movq %%mm4,%%mm2;\n" - - " pfmul %%mm7,%%mm5;\n" - " pfmul %%mm6,%%mm4;\n" - " pfsub %%mm1,%%mm5;\n" - " pfsub %%mm0,%%mm4;\n" - - " movq (%%eax),%%mm0;\n" - " movq %%mm0,%%mm1;\n" - " punpckldq %%mm0,%%mm1;\n" - " add $4,%%eax;\n" - " pfadd %%mm1,%%mm5;\n" - " pfadd %%mm1,%%mm4;\n" - - " dec %%ecx;\n" - - " jnz 1b;\n" - - " movq %%mm2,16(%%edx);\n" - " movq %%mm3,24(%%edx);\n" - " movq %%mm4,32(%%edx);\n" - " movq %%mm5,40(%%edx);\n" - - " femms;\n" - : - : "c" (samples), "a" (x), "d" (vv) - : "memory", "eax", "ecx"); - - s[0].v2 = vv[4]; - s[1].v2 = vv[5]; - s[2].v2 = vv[6]; - s[3].v2 = vv[7]; - s[0].v3 = vv[8]; - s[1].v3 = vv[9]; - s[2].v3 = vv[10]; - s[3].v3 = vv[11]; -} -#endif -/*- End of function --------------------------------------------------------*/ - -void zap_goertzel_update(goertzel_state_t *s, - int16_t x[], - int samples) -{ - int i; - float v1; - - for (i = 0; i < samples; i++) - { - v1 = s->v2; - s->v2 = s->v3; - s->v3 = s->fac*s->v2 - v1 + x[i]; - } -} -/*- End of function --------------------------------------------------------*/ - -float zap_goertzel_result (goertzel_state_t *s) -{ - return s->v3*s->v3 + s->v2*s->v2 - s->v2*s->v3*s->fac; -} -/*- End of function --------------------------------------------------------*/ - -void zap_dtmf_detect_init (dtmf_detect_state_t *s) -{ - int i; - float theta; - - s->hit1 = - s->hit2 = 0; - - for (i = 0; i < 4; i++) - { - theta = float(2.0*M_PI*(dtmf_row[i]/SAMPLE_RATE)); - dtmf_detect_row[i].fac = float(2.0*cos(theta)); - - theta = float(2.0*M_PI*(dtmf_col[i]/SAMPLE_RATE)); - dtmf_detect_col[i].fac = float(2.0*cos(theta)); - - theta = float(2.0*M_PI*(dtmf_row[i]*2.0/SAMPLE_RATE)); - dtmf_detect_row_2nd[i].fac = float(2.0*cos(theta)); - - theta = float(2.0*M_PI*(dtmf_col[i]*2.0/SAMPLE_RATE)); - dtmf_detect_col_2nd[i].fac = float(2.0*cos(theta)); - - goertzel_init (&s->row_out[i], &dtmf_detect_row[i]); - goertzel_init (&s->col_out[i], &dtmf_detect_col[i]); - goertzel_init (&s->row_out2nd[i], &dtmf_detect_row_2nd[i]); - goertzel_init (&s->col_out2nd[i], &dtmf_detect_col_2nd[i]); - -s->energy = 0.0; - } - - /* Same for the fax dector */ - theta = float(2.0*M_PI*(fax_freq/SAMPLE_RATE)); - fax_detect.fac = float(2.0 * cos(theta)); - goertzel_init (&s->fax_tone, &fax_detect); - - /* Same for the fax dector 2nd harmonic */ - theta = float(2.0*M_PI*(fax_freq * 2.0/SAMPLE_RATE)); - fax_detect_2nd.fac = float(2.0 * cos(theta)); - goertzel_init (&s->fax_tone2nd, &fax_detect_2nd); - - s->current_sample = 0; - s->detected_digits = 0; - s->lost_digits = 0; - s->digits[0] = '\0'; - s->mhit = 0; -} -/*- End of function --------------------------------------------------------*/ - -int zap_dtmf_detect (dtmf_detect_state_t *s, - int16_t amp[], - int samples, - int isradio) -{ - - float row_energy[4]; - float col_energy[4]; - float fax_energy; - float fax_energy_2nd; - float famp; - float v1; - int i; - int j; - int sample; - int best_row; - int best_col; - int hit; - int limit; - - hit = 0; - for (sample = 0; sample < samples; sample = limit) - { - /* 102 is optimised to meet the DTMF specs. */ - if ((samples - sample) >= (102 - s->current_sample)) - limit = sample + (102 - s->current_sample); - else - limit = samples; -#if defined(USE_3DNOW) - _dtmf_goertzel_update (s->row_out, amp + sample, limit - sample); - _dtmf_goertzel_update (s->col_out, amp + sample, limit - sample); - _dtmf_goertzel_update (s->row_out2nd, amp + sample, limit2 - sample); - _dtmf_goertzel_update (s->col_out2nd, amp + sample, limit2 - sample); -/* XXX Need to fax detect for 3dnow too XXX */ -#warning "Fax Support Broken" -#else - /* The following unrolled loop takes only 35% (rough estimate) of the - time of a rolled loop on the machine on which it was developed */ - for (j = sample; j < limit; j++) - { - famp = amp[j]; - - s->energy += famp*famp; - - /* With GCC 2.95, the following unrolled code seems to take about 35% - (rough estimate) as long as a neat little 0-3 loop */ - v1 = s->row_out[0].v2; - s->row_out[0].v2 = s->row_out[0].v3; - s->row_out[0].v3 = s->row_out[0].fac*s->row_out[0].v2 - v1 + famp; - - v1 = s->col_out[0].v2; - s->col_out[0].v2 = s->col_out[0].v3; - s->col_out[0].v3 = s->col_out[0].fac*s->col_out[0].v2 - v1 + famp; - - v1 = s->row_out[1].v2; - s->row_out[1].v2 = s->row_out[1].v3; - s->row_out[1].v3 = s->row_out[1].fac*s->row_out[1].v2 - v1 + famp; - - v1 = s->col_out[1].v2; - s->col_out[1].v2 = s->col_out[1].v3; - s->col_out[1].v3 = s->col_out[1].fac*s->col_out[1].v2 - v1 + famp; - - v1 = s->row_out[2].v2; - s->row_out[2].v2 = s->row_out[2].v3; - s->row_out[2].v3 = s->row_out[2].fac*s->row_out[2].v2 - v1 + famp; - - v1 = s->col_out[2].v2; - s->col_out[2].v2 = s->col_out[2].v3; - s->col_out[2].v3 = s->col_out[2].fac*s->col_out[2].v2 - v1 + famp; - - v1 = s->row_out[3].v2; - s->row_out[3].v2 = s->row_out[3].v3; - s->row_out[3].v3 = s->row_out[3].fac*s->row_out[3].v2 - v1 + famp; - - v1 = s->col_out[3].v2; - s->col_out[3].v2 = s->col_out[3].v3; - s->col_out[3].v3 = s->col_out[3].fac*s->col_out[3].v2 - v1 + famp; - - v1 = s->col_out2nd[0].v2; - s->col_out2nd[0].v2 = s->col_out2nd[0].v3; - s->col_out2nd[0].v3 = s->col_out2nd[0].fac*s->col_out2nd[0].v2 - v1 + famp; - - v1 = s->row_out2nd[0].v2; - s->row_out2nd[0].v2 = s->row_out2nd[0].v3; - s->row_out2nd[0].v3 = s->row_out2nd[0].fac*s->row_out2nd[0].v2 - v1 + famp; - - v1 = s->col_out2nd[1].v2; - s->col_out2nd[1].v2 = s->col_out2nd[1].v3; - s->col_out2nd[1].v3 = s->col_out2nd[1].fac*s->col_out2nd[1].v2 - v1 + famp; - - v1 = s->row_out2nd[1].v2; - s->row_out2nd[1].v2 = s->row_out2nd[1].v3; - s->row_out2nd[1].v3 = s->row_out2nd[1].fac*s->row_out2nd[1].v2 - v1 + famp; - - v1 = s->col_out2nd[2].v2; - s->col_out2nd[2].v2 = s->col_out2nd[2].v3; - s->col_out2nd[2].v3 = s->col_out2nd[2].fac*s->col_out2nd[2].v2 - v1 + famp; - - v1 = s->row_out2nd[2].v2; - s->row_out2nd[2].v2 = s->row_out2nd[2].v3; - s->row_out2nd[2].v3 = s->row_out2nd[2].fac*s->row_out2nd[2].v2 - v1 + famp; - - v1 = s->col_out2nd[3].v2; - s->col_out2nd[3].v2 = s->col_out2nd[3].v3; - s->col_out2nd[3].v3 = s->col_out2nd[3].fac*s->col_out2nd[3].v2 - v1 + famp; - - v1 = s->row_out2nd[3].v2; - s->row_out2nd[3].v2 = s->row_out2nd[3].v3; - s->row_out2nd[3].v3 = s->row_out2nd[3].fac*s->row_out2nd[3].v2 - v1 + famp; - -/* Update fax tone */ - v1 = s->fax_tone.v2; - s->fax_tone.v2 = s->fax_tone.v3; - s->fax_tone.v3 = s->fax_tone.fac*s->fax_tone.v2 - v1 + famp; - - v1 = s->fax_tone.v2; - s->fax_tone2nd.v2 = s->fax_tone2nd.v3; - s->fax_tone2nd.v3 = s->fax_tone2nd.fac*s->fax_tone2nd.v2 - v1 + famp; - } -#endif - s->current_sample += (limit - sample); - if (s->current_sample < 102) - continue; - -/* Detect the fax energy, too */ -fax_energy = zap_goertzel_result(&s->fax_tone); - - /* We are at the end of a DTMF detection block */ - /* Find the peak row and the peak column */ - row_energy[0] = zap_goertzel_result (&s->row_out[0]); - col_energy[0] = zap_goertzel_result (&s->col_out[0]); - -for (best_row = best_col = 0, i = 1; i < 4; i++) -{ - row_energy[i] = zap_goertzel_result (&s->row_out[i]); - if (row_energy[i] > row_energy[best_row]) - best_row = i; - col_energy[i] = zap_goertzel_result (&s->col_out[i]); - if (col_energy[i] > col_energy[best_col]) - best_col = i; - } - hit = 0; - /* Basic signal level test and the twist test */ - if (row_energy[best_row] >= DTMF_THRESHOLD - && - col_energy[best_col] >= DTMF_THRESHOLD - && - col_energy[best_col] < row_energy[best_row]*DTMF_REVERSE_TWIST - && - col_energy[best_col]*DTMF_NORMAL_TWIST > row_energy[best_row]) - { - /* Relative peak test */ - for (i = 0; i < 4; i++) - { - if ((i != best_col && col_energy[i]*DTMF_RELATIVE_PEAK_COL > col_energy[best_col]) - || - (i != best_row && row_energy[i]*DTMF_RELATIVE_PEAK_ROW > row_energy[best_row])) - { - break; - } - } - /* ... and second harmonic test */ - if (i >= 4 - && -(row_energy[best_row] + col_energy[best_col]) > 42.0*s->energy - && - zap_goertzel_result (&s->col_out2nd[best_col])*DTMF_2ND_HARMONIC_COL < col_energy[best_col] - && - zap_goertzel_result (&s->row_out2nd[best_row])*DTMF_2ND_HARMONIC_ROW < row_energy[best_row]) - { - hit = dtmf_positions[(best_row << 2) + best_col]; - /* Look for two successive similar results */ - /* The logic in the next test is: - We need two successive identical clean detects, with - something different preceeding it. This can work with - back to back differing digits. More importantly, it - can work with nasty phones that give a very wobbly start - to a digit. */ - if (hit == s->hit3 && s->hit3 != s->hit2) - { - s->mhit = hit; - s->digit_hits[(best_row << 2) + best_col]++; - s->detected_digits++; - if (s->current_digits < MAX_DTMF_DIGITS) - { - s->digits[s->current_digits++] = hit; - s->digits[s->current_digits] = '\0'; - } - else - { - s->lost_digits++; - } - } - } - } -if (!hit && (fax_energy >= FAX_THRESHOLD) && (fax_energy > s->energy * 21.0)) { -fax_energy_2nd = zap_goertzel_result(&s->fax_tone2nd); -if (fax_energy_2nd * FAX_2ND_HARMONIC < fax_energy) { -#if 0 -printf("Fax energy/Second Harmonic: %f/%f\n", fax_energy, fax_energy_2nd); -#endif -/* XXX Probably need better checking than just this the energy XXX */ -hit = 'f'; -s->fax_hits++; -} /* Don't reset fax hits counter */ -} else { -if (s->fax_hits > 5) { - s->mhit = 'f'; - s->detected_digits++; - if (s->current_digits < MAX_DTMF_DIGITS) - { - s->digits[s->current_digits++] = hit; - s->digits[s->current_digits] = '\0'; - } - else - { - s->lost_digits++; - } -} -s->fax_hits = 0; -} - s->hit1 = s->hit2; - s->hit2 = s->hit3; - s->hit3 = hit; - /* Reinitialise the detector for the next block */ - for (i = 0; i < 4; i++) - { - goertzel_init (&s->row_out[i], &dtmf_detect_row[i]); - goertzel_init (&s->col_out[i], &dtmf_detect_col[i]); - goertzel_init (&s->row_out2nd[i], &dtmf_detect_row_2nd[i]); - goertzel_init (&s->col_out2nd[i], &dtmf_detect_col_2nd[i]); - } - goertzel_init (&s->fax_tone, &fax_detect); - goertzel_init (&s->fax_tone2nd, &fax_detect_2nd); -s->energy = 0.0; - s->current_sample = 0; - } - if ((!s->mhit) || (s->mhit != hit)) - { -s->mhit = 0; -return(0); - } - return (hit); -} -/*- End of function --------------------------------------------------------*/ - -int zap_dtmf_get (dtmf_detect_state_t *s, - char *buf, - int max) -{ - if (max > s->current_digits) - max = s->current_digits; - if (max > 0) - { - memcpy (buf, s->digits, max); - memmove (s->digits, s->digits + max, s->current_digits - max); - s->current_digits -= max; - } - buf[max] = '\0'; - return max; -} - - +} + +#ifndef TRUE + +# define FALSE 0 +# define TRUE (!FALSE) + +#endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +//#define USE_3DNOW + +/* Basic DTMF specs: + * + * Minimum tone on = 40ms + * Minimum tone off = 50ms + * Maximum digit rate = 10 per second + * Normal twist <= 8dB accepted + * Reverse twist <= 4dB accepted + * S/N >= 15dB will detect OK + * Attenuation <= 26dB will detect OK + * Frequency tolerance +- 1.5% will detect, +-3.5% will reject + */ + +#define SAMPLE_RATE 8000.0 + +#define DTMF_THRESHOLD 8.0e7 +#define FAX_THRESHOLD 8.0e7 +#define FAX_2ND_HARMONIC 2.0 /* 4dB */ +#define DTMF_NORMAL_TWIST 6.3 /* 8dB */ +#define DTMF_REVERSE_TWIST ((isradio) ? 4.0 : 2.5) /* 4dB normal */ +#define DTMF_RELATIVE_PEAK_ROW 6.3 /* 8dB */ +#define DTMF_RELATIVE_PEAK_COL 6.3 /* 8dB */ +#define DTMF_2ND_HARMONIC_ROW ((isradio) ? 1.7 : 2.5) /* 4dB normal */ +#define DTMF_2ND_HARMONIC_COL 63.1 /* 18dB */ + +static tone_detection_descriptor_t dtmf_detect_row[4]; +static tone_detection_descriptor_t dtmf_detect_col[4]; +static tone_detection_descriptor_t dtmf_detect_row_2nd[4]; +static tone_detection_descriptor_t dtmf_detect_col_2nd[4]; +static tone_detection_descriptor_t fax_detect; +static tone_detection_descriptor_t fax_detect_2nd; + +static float dtmf_row[] = +{ + 697.0, 770.0, 852.0, 941.0 +}; +static float dtmf_col[] = +{ + 1209.0, 1336.0, 1477.0, 1633.0 +}; + +static float fax_freq = 1100.0; + +static char dtmf_positions[] = "123A" "456B" "789C" "*0#D"; + +static void goertzel_init(goertzel_state_t *s, + tone_detection_descriptor_t *t) +{ + s->v2 = + s->v3 = 0.0; + s->fac = t->fac; +} +/*- End of function --------------------------------------------------------*/ + +#if defined(USE_3DNOW) +static inline void _dtmf_goertzel_update(goertzel_state_t *s, + float x[], + int samples) +{ + int n; + float v; + int i; + float vv[16]; + + vv[4] = s[0].v2; + vv[5] = s[1].v2; + vv[6] = s[2].v2; + vv[7] = s[3].v2; + vv[8] = s[0].v3; + vv[9] = s[1].v3; + vv[10] = s[2].v3; + vv[11] = s[3].v3; + vv[12] = s[0].fac; + vv[13] = s[1].fac; + vv[14] = s[2].fac; + vv[15] = s[3].fac; + + //v1 = s->v2; + //s->v2 = s->v3; + //s->v3 = s->fac*s->v2 - v1 + x[0]; + + __asm__ __volatile__ ( + " femms;\n" + + " movq 16(%%edx),%%mm2;\n" + " movq 24(%%edx),%%mm3;\n" + " movq 32(%%edx),%%mm4;\n" + " movq 40(%%edx),%%mm5;\n" + " movq 48(%%edx),%%mm6;\n" + " movq 56(%%edx),%%mm7;\n" + + " jmp 1f;\n" + " .align 32;\n" + + " 1: ;\n" + " prefetch (%%eax);\n" + " movq %%mm3,%%mm1;\n" + " movq %%mm2,%%mm0;\n" + " movq %%mm5,%%mm3;\n" + " movq %%mm4,%%mm2;\n" + + " pfmul %%mm7,%%mm5;\n" + " pfmul %%mm6,%%mm4;\n" + " pfsub %%mm1,%%mm5;\n" + " pfsub %%mm0,%%mm4;\n" + + " movq (%%eax),%%mm0;\n" + " movq %%mm0,%%mm1;\n" + " punpckldq %%mm0,%%mm1;\n" + " add $4,%%eax;\n" + " pfadd %%mm1,%%mm5;\n" + " pfadd %%mm1,%%mm4;\n" + + " dec %%ecx;\n" + + " jnz 1b;\n" + + " movq %%mm2,16(%%edx);\n" + " movq %%mm3,24(%%edx);\n" + " movq %%mm4,32(%%edx);\n" + " movq %%mm5,40(%%edx);\n" + + " femms;\n" + : + : "c" (samples), "a" (x), "d" (vv) + : "memory", "eax", "ecx"); + + s[0].v2 = vv[4]; + s[1].v2 = vv[5]; + s[2].v2 = vv[6]; + s[3].v2 = vv[7]; + s[0].v3 = vv[8]; + s[1].v3 = vv[9]; + s[2].v3 = vv[10]; + s[3].v3 = vv[11]; +} +#endif +/*- End of function --------------------------------------------------------*/ + +void zap_goertzel_update(goertzel_state_t *s, + int16_t x[], + int samples) +{ + int i; + float v1; + + for (i = 0; i < samples; i++) + { + v1 = s->v2; + s->v2 = s->v3; + s->v3 = s->fac*s->v2 - v1 + x[i]; + } +} +/*- End of function --------------------------------------------------------*/ + +float zap_goertzel_result (goertzel_state_t *s) +{ + return s->v3*s->v3 + s->v2*s->v2 - s->v2*s->v3*s->fac; +} +/*- End of function --------------------------------------------------------*/ + +void zap_dtmf_detect_init (dtmf_detect_state_t *s) +{ + int i; + float theta; + + s->hit1 = + s->hit2 = 0; + + for (i = 0; i < 4; i++) + { + theta = float(2.0*M_PI*(dtmf_row[i]/SAMPLE_RATE)); + dtmf_detect_row[i].fac = float(2.0*cos(theta)); + + theta = float(2.0*M_PI*(dtmf_col[i]/SAMPLE_RATE)); + dtmf_detect_col[i].fac = float(2.0*cos(theta)); + + theta = float(2.0*M_PI*(dtmf_row[i]*2.0/SAMPLE_RATE)); + dtmf_detect_row_2nd[i].fac = float(2.0*cos(theta)); + + theta = float(2.0*M_PI*(dtmf_col[i]*2.0/SAMPLE_RATE)); + dtmf_detect_col_2nd[i].fac = float(2.0*cos(theta)); + + goertzel_init (&s->row_out[i], &dtmf_detect_row[i]); + goertzel_init (&s->col_out[i], &dtmf_detect_col[i]); + goertzel_init (&s->row_out2nd[i], &dtmf_detect_row_2nd[i]); + goertzel_init (&s->col_out2nd[i], &dtmf_detect_col_2nd[i]); + +s->energy = 0.0; + } + + /* Same for the fax dector */ + theta = float(2.0*M_PI*(fax_freq/SAMPLE_RATE)); + fax_detect.fac = float(2.0 * cos(theta)); + goertzel_init (&s->fax_tone, &fax_detect); + + /* Same for the fax dector 2nd harmonic */ + theta = float(2.0*M_PI*(fax_freq * 2.0/SAMPLE_RATE)); + fax_detect_2nd.fac = float(2.0 * cos(theta)); + goertzel_init (&s->fax_tone2nd, &fax_detect_2nd); + + s->current_sample = 0; + s->detected_digits = 0; + s->lost_digits = 0; + s->digits[0] = '\0'; + s->mhit = 0; +} +/*- End of function --------------------------------------------------------*/ + +int zap_dtmf_detect (dtmf_detect_state_t *s, + int16_t amp[], + int samples, + int isradio) +{ + + float row_energy[4]; + float col_energy[4]; + float fax_energy; + float fax_energy_2nd; + float famp; + float v1; + int i; + int j; + int sample; + int best_row; + int best_col; + int hit; + int limit; + + hit = 0; + for (sample = 0; sample < samples; sample = limit) + { + /* 102 is optimised to meet the DTMF specs. */ + if ((samples - sample) >= (102 - s->current_sample)) + limit = sample + (102 - s->current_sample); + else + limit = samples; +#if defined(USE_3DNOW) + _dtmf_goertzel_update (s->row_out, amp + sample, limit - sample); + _dtmf_goertzel_update (s->col_out, amp + sample, limit - sample); + _dtmf_goertzel_update (s->row_out2nd, amp + sample, limit2 - sample); + _dtmf_goertzel_update (s->col_out2nd, amp + sample, limit2 - sample); +/* XXX Need to fax detect for 3dnow too XXX */ +#warning "Fax Support Broken" +#else + /* The following unrolled loop takes only 35% (rough estimate) of the + time of a rolled loop on the machine on which it was developed */ + for (j = sample; j < limit; j++) + { + famp = amp[j]; + + s->energy += famp*famp; + + /* With GCC 2.95, the following unrolled code seems to take about 35% + (rough estimate) as long as a neat little 0-3 loop */ + v1 = s->row_out[0].v2; + s->row_out[0].v2 = s->row_out[0].v3; + s->row_out[0].v3 = s->row_out[0].fac*s->row_out[0].v2 - v1 + famp; + + v1 = s->col_out[0].v2; + s->col_out[0].v2 = s->col_out[0].v3; + s->col_out[0].v3 = s->col_out[0].fac*s->col_out[0].v2 - v1 + famp; + + v1 = s->row_out[1].v2; + s->row_out[1].v2 = s->row_out[1].v3; + s->row_out[1].v3 = s->row_out[1].fac*s->row_out[1].v2 - v1 + famp; + + v1 = s->col_out[1].v2; + s->col_out[1].v2 = s->col_out[1].v3; + s->col_out[1].v3 = s->col_out[1].fac*s->col_out[1].v2 - v1 + famp; + + v1 = s->row_out[2].v2; + s->row_out[2].v2 = s->row_out[2].v3; + s->row_out[2].v3 = s->row_out[2].fac*s->row_out[2].v2 - v1 + famp; + + v1 = s->col_out[2].v2; + s->col_out[2].v2 = s->col_out[2].v3; + s->col_out[2].v3 = s->col_out[2].fac*s->col_out[2].v2 - v1 + famp; + + v1 = s->row_out[3].v2; + s->row_out[3].v2 = s->row_out[3].v3; + s->row_out[3].v3 = s->row_out[3].fac*s->row_out[3].v2 - v1 + famp; + + v1 = s->col_out[3].v2; + s->col_out[3].v2 = s->col_out[3].v3; + s->col_out[3].v3 = s->col_out[3].fac*s->col_out[3].v2 - v1 + famp; + + v1 = s->col_out2nd[0].v2; + s->col_out2nd[0].v2 = s->col_out2nd[0].v3; + s->col_out2nd[0].v3 = s->col_out2nd[0].fac*s->col_out2nd[0].v2 - v1 + famp; + + v1 = s->row_out2nd[0].v2; + s->row_out2nd[0].v2 = s->row_out2nd[0].v3; + s->row_out2nd[0].v3 = s->row_out2nd[0].fac*s->row_out2nd[0].v2 - v1 + famp; + + v1 = s->col_out2nd[1].v2; + s->col_out2nd[1].v2 = s->col_out2nd[1].v3; + s->col_out2nd[1].v3 = s->col_out2nd[1].fac*s->col_out2nd[1].v2 - v1 + famp; + + v1 = s->row_out2nd[1].v2; + s->row_out2nd[1].v2 = s->row_out2nd[1].v3; + s->row_out2nd[1].v3 = s->row_out2nd[1].fac*s->row_out2nd[1].v2 - v1 + famp; + + v1 = s->col_out2nd[2].v2; + s->col_out2nd[2].v2 = s->col_out2nd[2].v3; + s->col_out2nd[2].v3 = s->col_out2nd[2].fac*s->col_out2nd[2].v2 - v1 + famp; + + v1 = s->row_out2nd[2].v2; + s->row_out2nd[2].v2 = s->row_out2nd[2].v3; + s->row_out2nd[2].v3 = s->row_out2nd[2].fac*s->row_out2nd[2].v2 - v1 + famp; + + v1 = s->col_out2nd[3].v2; + s->col_out2nd[3].v2 = s->col_out2nd[3].v3; + s->col_out2nd[3].v3 = s->col_out2nd[3].fac*s->col_out2nd[3].v2 - v1 + famp; + + v1 = s->row_out2nd[3].v2; + s->row_out2nd[3].v2 = s->row_out2nd[3].v3; + s->row_out2nd[3].v3 = s->row_out2nd[3].fac*s->row_out2nd[3].v2 - v1 + famp; + +/* Update fax tone */ + v1 = s->fax_tone.v2; + s->fax_tone.v2 = s->fax_tone.v3; + s->fax_tone.v3 = s->fax_tone.fac*s->fax_tone.v2 - v1 + famp; + + v1 = s->fax_tone.v2; + s->fax_tone2nd.v2 = s->fax_tone2nd.v3; + s->fax_tone2nd.v3 = s->fax_tone2nd.fac*s->fax_tone2nd.v2 - v1 + famp; + } +#endif + s->current_sample += (limit - sample); + if (s->current_sample < 102) + continue; + +/* Detect the fax energy, too */ +fax_energy = zap_goertzel_result(&s->fax_tone); + + /* We are at the end of a DTMF detection block */ + /* Find the peak row and the peak column */ + row_energy[0] = zap_goertzel_result (&s->row_out[0]); + col_energy[0] = zap_goertzel_result (&s->col_out[0]); + +for (best_row = best_col = 0, i = 1; i < 4; i++) +{ + row_energy[i] = zap_goertzel_result (&s->row_out[i]); + if (row_energy[i] > row_energy[best_row]) + best_row = i; + col_energy[i] = zap_goertzel_result (&s->col_out[i]); + if (col_energy[i] > col_energy[best_col]) + best_col = i; + } + hit = 0; + /* Basic signal level test and the twist test */ + if (row_energy[best_row] >= DTMF_THRESHOLD + && + col_energy[best_col] >= DTMF_THRESHOLD + && + col_energy[best_col] < row_energy[best_row]*DTMF_REVERSE_TWIST + && + col_energy[best_col]*DTMF_NORMAL_TWIST > row_energy[best_row]) + { + /* Relative peak test */ + for (i = 0; i < 4; i++) + { + if ((i != best_col && col_energy[i]*DTMF_RELATIVE_PEAK_COL > col_energy[best_col]) + || + (i != best_row && row_energy[i]*DTMF_RELATIVE_PEAK_ROW > row_energy[best_row])) + { + break; + } + } + /* ... and second harmonic test */ + if (i >= 4 + && +(row_energy[best_row] + col_energy[best_col]) > 42.0*s->energy + && + zap_goertzel_result (&s->col_out2nd[best_col])*DTMF_2ND_HARMONIC_COL < col_energy[best_col] + && + zap_goertzel_result (&s->row_out2nd[best_row])*DTMF_2ND_HARMONIC_ROW < row_energy[best_row]) + { + hit = dtmf_positions[(best_row << 2) + best_col]; + /* Look for two successive similar results */ + /* The logic in the next test is: + We need two successive identical clean detects, with + something different preceeding it. This can work with + back to back differing digits. More importantly, it + can work with nasty phones that give a very wobbly start + to a digit. */ + if (hit == s->hit3 && s->hit3 != s->hit2) + { + s->mhit = hit; + s->digit_hits[(best_row << 2) + best_col]++; + s->detected_digits++; + if (s->current_digits < MAX_DTMF_DIGITS) + { + s->digits[s->current_digits++] = hit; + s->digits[s->current_digits] = '\0'; + } + else + { + s->lost_digits++; + } + } + } + } +if (!hit && (fax_energy >= FAX_THRESHOLD) && (fax_energy > s->energy * 21.0)) { +fax_energy_2nd = zap_goertzel_result(&s->fax_tone2nd); +if (fax_energy_2nd * FAX_2ND_HARMONIC < fax_energy) { +#if 0 +printf("Fax energy/Second Harmonic: %f/%f\n", fax_energy, fax_energy_2nd); +#endif +/* XXX Probably need better checking than just this the energy XXX */ +hit = 'f'; +s->fax_hits++; +} /* Don't reset fax hits counter */ +} else { +if (s->fax_hits > 5) { + s->mhit = 'f'; + s->detected_digits++; + if (s->current_digits < MAX_DTMF_DIGITS) + { + s->digits[s->current_digits++] = hit; + s->digits[s->current_digits] = '\0'; + } + else + { + s->lost_digits++; + } +} +s->fax_hits = 0; +} + s->hit1 = s->hit2; + s->hit2 = s->hit3; + s->hit3 = hit; + /* Reinitialise the detector for the next block */ + for (i = 0; i < 4; i++) + { + goertzel_init (&s->row_out[i], &dtmf_detect_row[i]); + goertzel_init (&s->col_out[i], &dtmf_detect_col[i]); + goertzel_init (&s->row_out2nd[i], &dtmf_detect_row_2nd[i]); + goertzel_init (&s->col_out2nd[i], &dtmf_detect_col_2nd[i]); + } + goertzel_init (&s->fax_tone, &fax_detect); + goertzel_init (&s->fax_tone2nd, &fax_detect_2nd); +s->energy = 0.0; + s->current_sample = 0; + } + if ((!s->mhit) || (s->mhit != hit)) + { +s->mhit = 0; +return(0); + } + return (hit); +} +/*- End of function --------------------------------------------------------*/ + +int zap_dtmf_get (dtmf_detect_state_t *s, + char *buf, + int max) +{ + if (max > s->current_digits) + max = s->current_digits; + if (max > 0) + { + memcpy (buf, s->digits, max); + memmove (s->digits, s->digits + max, s->current_digits - max); + s->current_digits -= max; + } + buf[max] = '\0'; + return max; +} + + diff --git a/src/engine/media/MT_SevanaMos.cpp b/src/engine/media/MT_SevanaMos.cpp index 6ffd1d86..41ee76ad 100644 --- a/src/engine/media/MT_SevanaMos.cpp +++ b/src/engine/media/MT_SevanaMos.cpp @@ -6,9 +6,7 @@ #if defined(USE_PVQA_LIBRARY) #if defined(TARGET_SERVER) -# include -# include -using namespace boost::filesystem; +# include #endif #include "../engine/helper/HL_Log.h" @@ -67,6 +65,7 @@ static std::string execCommand(const std::string& cmd) void SevanaMosUtility::run(const std::string& pcmPath, const std::string& intervalPath, std::string& estimation, std::string& intervals) { +/* #if defined(TARGET_SERVER) path sevana = current_path() / "sevana"; #if defined(TARGET_LINUX) || defined(TARGET_OSX) @@ -113,11 +112,16 @@ void SevanaMosUtility::run(const std::string& pcmPath, const std::string& interv intervals = str; } #endif +*/ + + } float getSevanaMos(const std::string& audioPath, const std::string& intervalReportPath, std::string& intervalReport) { + return 0.0f; + /* // Find Sevana MOS estimation ICELogDebug( << "Running MOS utitlity on resulted PCM file " << audioPath ); try @@ -131,7 +135,7 @@ float getSevanaMos(const std::string& audioPath, const std::string& intervalRepo { ICELogError( << "MOS utility failed on PCM file " << audioPath << ". Error msg: " << e.what() ); return 0.0; - } + }*/ } // ------------------- SevanaPVQA -------------------