--- /dev/null
+/*****************************************************************************\r
+* *\r
+* DIGITAL SIGNAL PROCESSING TOOLS *\r
+* Version 1.03, 2001/06/15 *\r
+* (c) 1999 - Laurent de Soras *\r
+* *\r
+* FFTReal.cpp *\r
+* Fourier transformation of real number arrays. *\r
+* Portable ISO C++ *\r
+* *\r
+* Tab = 3 *\r
+*****************************************************************************/\r
+\r
+\r
+\r
+/*\\\ INCLUDE FILES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/\r
+\r
+#include "FFTReal.h"\r
+\r
+#include <cassert>\r
+#include <cmath>\r
+\r
+\r
+\r
+#if defined (_MSC_VER)\r
+#pragma pack (push, 8)\r
+#endif // _MSC_VER\r
+\r
+\r
+\r
+/*\\\ PUBLIC MEMBER FUNCTIONS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/\r
+\r
+\r
+\r
+/*==========================================================================*/\r
+/* Name: Constructor */\r
+/* Input parameters: */\r
+/* - length: length of the array on which we want to do a FFT. */\r
+/* Range: power of 2 only, > 0. */\r
+/* Throws: std::bad_alloc, anything */\r
+/*==========================================================================*/\r
+\r
+FFTReal::FFTReal (const long length)\r
+: _length (length)\r
+, _nbr_bits (int (floor (log (length) / log (2) + 0.5)))\r
+, _bit_rev_lut (int (floor (log (length) / log (2) + 0.5)))\r
+, _trigo_lut (int (floor (log (length) / log (2) + 0.5)))\r
+, _sqrt2_2 (flt_t (sqrt (2) * 0.5))\r
+{\r
+ assert ((1L << _nbr_bits) == length);\r
+\r
+ _buffer_ptr = 0;\r
+ if (_nbr_bits > 2)\r
+ {\r
+ _buffer_ptr = new flt_t [_length];\r
+ }\r
+}\r
+\r
+\r
+\r
+/*==========================================================================*/\r
+/* Name: Destructor */\r
+/*==========================================================================*/\r
+\r
+FFTReal::~FFTReal (void)\r
+{\r
+ delete [] _buffer_ptr;\r
+ _buffer_ptr = 0;\r
+}\r
+\r
+\r
+\r
+/*==========================================================================*/\r
+/* Name: do_fft */\r
+/* Description: Compute the FFT of the array. */\r
+/* Input parameters: */\r
+/* - x: pointer on the source array (time). */\r
+/* Output parameters: */\r
+/* - f: pointer on the destination array (frequencies). */\r
+/* f [0...length(x)/2] = real values, */\r
+/* f [length(x)/2+1...length(x)-1] = imaginary values of */\r
+/* coefficents 1...length(x)/2-1. */\r
+/* Throws: Nothing */\r
+/*==========================================================================*/\r
+\r
+void FFTReal::do_fft (flt_t f [], const flt_t x []) const\r
+{\r
+\r
+/*______________________________________________\r
+ *\r
+ * General case\r
+ *______________________________________________\r
+ */\r
+\r
+ if (_nbr_bits > 2)\r
+ {\r
+ flt_t * sf;\r
+ flt_t * df;\r
+\r
+ if (_nbr_bits & 1)\r
+ {\r
+ df = _buffer_ptr;\r
+ sf = f;\r
+ }\r
+ else\r
+ {\r
+ df = f;\r
+ sf = _buffer_ptr;\r
+ }\r
+\r
+ /* Do the transformation in several pass */\r
+ {\r
+ int pass;\r
+ long nbr_coef;\r
+ long h_nbr_coef;\r
+ long d_nbr_coef;\r
+ long coef_index;\r
+\r
+ /* First and second pass at once */\r
+ {\r
+ const long * const bit_rev_lut_ptr = _bit_rev_lut.get_ptr ();\r
+ coef_index = 0;\r
+ do\r
+ {\r
+ const long rev_index_0 = bit_rev_lut_ptr [coef_index];\r
+ const long rev_index_1 = bit_rev_lut_ptr [coef_index + 1];\r
+ const long rev_index_2 = bit_rev_lut_ptr [coef_index + 2];\r
+ const long rev_index_3 = bit_rev_lut_ptr [coef_index + 3];\r
+\r
+ flt_t * const df2 = df + coef_index;\r
+ df2 [1] = x [rev_index_0] - x [rev_index_1];\r
+ df2 [3] = x [rev_index_2] - x [rev_index_3];\r
+\r
+ const flt_t sf_0 = x [rev_index_0] + x [rev_index_1];\r
+ const flt_t sf_2 = x [rev_index_2] + x [rev_index_3];\r
+\r
+ df2 [0] = sf_0 + sf_2;\r
+ df2 [2] = sf_0 - sf_2;\r
+ \r
+ coef_index += 4;\r
+ }\r
+ while (coef_index < _length);\r
+ }\r
+\r
+ /* Third pass */\r
+ {\r
+ coef_index = 0;\r
+ const flt_t sqrt2_2 = _sqrt2_2;\r
+ do\r
+ {\r
+ flt_t v;\r
+\r
+ sf [coef_index] = df [coef_index] + df [coef_index + 4];\r
+ sf [coef_index + 4] = df [coef_index] - df [coef_index + 4];\r
+ sf [coef_index + 2] = df [coef_index + 2];\r
+ sf [coef_index + 6] = df [coef_index + 6];\r
+\r
+ v = (df [coef_index + 5] - df [coef_index + 7]) * sqrt2_2;\r
+ sf [coef_index + 1] = df [coef_index + 1] + v;\r
+ sf [coef_index + 3] = df [coef_index + 1] - v;\r
+\r
+ v = (df [coef_index + 5] + df [coef_index + 7]) * sqrt2_2;\r
+ sf [coef_index + 5] = v + df [coef_index + 3];\r
+ sf [coef_index + 7] = v - df [coef_index + 3];\r
+\r
+ coef_index += 8;\r
+ }\r
+ while (coef_index < _length);\r
+ }\r
+\r
+ /* Next pass */\r
+ for (pass = 3; pass < _nbr_bits; ++pass)\r
+ {\r
+ coef_index = 0;\r
+ nbr_coef = 1 << pass;\r
+ h_nbr_coef = nbr_coef >> 1;\r
+ d_nbr_coef = nbr_coef << 1;\r
+ const flt_t * const cos_ptr = _trigo_lut.get_ptr (pass);\r
+ do\r
+ {\r
+ long i;\r
+ const flt_t * const sf1r = sf + coef_index;\r
+ const flt_t * const sf2r = sf1r + nbr_coef;\r
+ flt_t * const dfr = df + coef_index;\r
+ flt_t * const dfi = dfr + nbr_coef;\r
+\r
+ /* Extreme coefficients are always real */\r
+ dfr [0] = sf1r [0] + sf2r [0];\r
+ dfi [0] = sf1r [0] - sf2r [0]; // dfr [nbr_coef] =\r
+ dfr [h_nbr_coef] = sf1r [h_nbr_coef];\r
+ dfi [h_nbr_coef] = sf2r [h_nbr_coef];\r
+\r
+ /* Others are conjugate complex numbers */\r
+ const flt_t * const sf1i = sf1r + h_nbr_coef;\r
+ const flt_t * const sf2i = sf1i + nbr_coef;\r
+ for (i = 1; i < h_nbr_coef; ++ i)\r
+ {\r
+ const flt_t c = cos_ptr [i]; // cos (i*PI/nbr_coef);\r
+ const flt_t s = cos_ptr [h_nbr_coef - i]; // sin (i*PI/nbr_coef);\r
+ flt_t v;\r
+\r
+ v = sf2r [i] * c - sf2i [i] * s;\r
+ dfr [i] = sf1r [i] + v;\r
+ dfi [-i] = sf1r [i] - v; // dfr [nbr_coef - i] =\r
+\r
+ v = sf2r [i] * s + sf2i [i] * c;\r
+ dfi [i] = v + sf1i [i];\r
+ dfi [nbr_coef - i] = v - sf1i [i];\r
+ }\r
+\r
+ coef_index += d_nbr_coef;\r
+ }\r
+ while (coef_index < _length);\r
+\r
+ /* Prepare to the next pass */\r
+ {\r
+ flt_t * const temp_ptr = df;\r
+ df = sf;\r
+ sf = temp_ptr;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+/*______________________________________________\r
+ *\r
+ * Special cases\r
+ *______________________________________________\r
+ */\r
+\r
+ /* 4-point FFT */\r
+ else if (_nbr_bits == 2)\r
+ {\r
+ f [1] = x [0] - x [2];\r
+ f [3] = x [1] - x [3];\r
+\r
+ const flt_t b_0 = x [0] + x [2];\r
+ const flt_t b_2 = x [1] + x [3];\r
+ \r
+ f [0] = b_0 + b_2;\r
+ f [2] = b_0 - b_2;\r
+ }\r
+\r
+ /* 2-point FFT */\r
+ else if (_nbr_bits == 1)\r
+ {\r
+ f [0] = x [0] + x [1];\r
+ f [1] = x [0] - x [1];\r
+ }\r
+\r
+ /* 1-point FFT */\r
+ else\r
+ {\r
+ f [0] = x [0];\r
+ }\r
+}\r
+\r
+\r
+\r
+/*==========================================================================*/\r
+/* Name: do_ifft */\r
+/* Description: Compute the inverse FFT of the array. Notice that */\r
+/* IFFT (FFT (x)) = x * length (x). Data must be */\r
+/* post-scaled. */\r
+/* Input parameters: */\r
+/* - f: pointer on the source array (frequencies). */\r
+/* f [0...length(x)/2] = real values, */\r
+/* f [length(x)/2+1...length(x)] = imaginary values of */\r
+/* coefficents 1...length(x)-1. */\r
+/* Output parameters: */\r
+/* - x: pointer on the destination array (time). */\r
+/* Throws: Nothing */\r
+/*==========================================================================*/\r
+\r
+void FFTReal::do_ifft (const flt_t f [], flt_t x []) const\r
+{\r
+\r
+/*______________________________________________\r
+ *\r
+ * General case\r
+ *______________________________________________\r
+ */\r
+\r
+ if (_nbr_bits > 2)\r
+ {\r
+ flt_t * sf = const_cast <flt_t *> (f);\r
+ flt_t * df;\r
+ flt_t * df_temp;\r
+\r
+ if (_nbr_bits & 1)\r
+ {\r
+ df = _buffer_ptr;\r
+ df_temp = x;\r
+ }\r
+ else\r
+ {\r
+ df = x;\r
+ df_temp = _buffer_ptr;\r
+ }\r
+\r
+ /* Do the transformation in several pass */\r
+ {\r
+ int pass;\r
+ long nbr_coef;\r
+ long h_nbr_coef;\r
+ long d_nbr_coef;\r
+ long coef_index;\r
+\r
+ /* First pass */\r
+ for (pass = _nbr_bits - 1; pass >= 3; --pass)\r
+ {\r
+ coef_index = 0;\r
+ nbr_coef = 1 << pass;\r
+ h_nbr_coef = nbr_coef >> 1;\r
+ d_nbr_coef = nbr_coef << 1;\r
+ const flt_t *const cos_ptr = _trigo_lut.get_ptr (pass);\r
+ do\r
+ {\r
+ long i;\r
+ const flt_t * const sfr = sf + coef_index;\r
+ const flt_t * const sfi = sfr + nbr_coef;\r
+ flt_t * const df1r = df + coef_index;\r
+ flt_t * const df2r = df1r + nbr_coef;\r
+\r
+ /* Extreme coefficients are always real */\r
+ df1r [0] = sfr [0] + sfi [0]; // + sfr [nbr_coef]\r
+ df2r [0] = sfr [0] - sfi [0]; // - sfr [nbr_coef]\r
+ df1r [h_nbr_coef] = sfr [h_nbr_coef] * 2;\r
+ df2r [h_nbr_coef] = sfi [h_nbr_coef] * 2;\r
+\r
+ /* Others are conjugate complex numbers */\r
+ flt_t * const df1i = df1r + h_nbr_coef;\r
+ flt_t * const df2i = df1i + nbr_coef;\r
+ for (i = 1; i < h_nbr_coef; ++ i)\r
+ {\r
+ df1r [i] = sfr [i] + sfi [-i]; // + sfr [nbr_coef - i]\r
+ df1i [i] = sfi [i] - sfi [nbr_coef - i];\r
+\r
+ const flt_t c = cos_ptr [i]; // cos (i*PI/nbr_coef);\r
+ const flt_t s = cos_ptr [h_nbr_coef - i]; // sin (i*PI/nbr_coef);\r
+ const flt_t vr = sfr [i] - sfi [-i]; // - sfr [nbr_coef - i]\r
+ const flt_t vi = sfi [i] + sfi [nbr_coef - i];\r
+\r
+ df2r [i] = vr * c + vi * s;\r
+ df2i [i] = vi * c - vr * s;\r
+ }\r
+\r
+ coef_index += d_nbr_coef;\r
+ }\r
+ while (coef_index < _length);\r
+\r
+ /* Prepare to the next pass */\r
+ if (pass < _nbr_bits - 1)\r
+ {\r
+ flt_t * const temp_ptr = df;\r
+ df = sf;\r
+ sf = temp_ptr;\r
+ }\r
+ else\r
+ {\r
+ sf = df;\r
+ df = df_temp;\r
+ }\r
+ }\r
+\r
+ /* Antepenultimate pass */\r
+ {\r
+ const flt_t sqrt2_2 = _sqrt2_2;\r
+ coef_index = 0;\r
+ do\r
+ {\r
+ df [coef_index] = sf [coef_index] + sf [coef_index + 4];\r
+ df [coef_index + 4] = sf [coef_index] - sf [coef_index + 4];\r
+ df [coef_index + 2] = sf [coef_index + 2] * 2;\r
+ df [coef_index + 6] = sf [coef_index + 6] * 2;\r
+\r
+ df [coef_index + 1] = sf [coef_index + 1] + sf [coef_index + 3];\r
+ df [coef_index + 3] = sf [coef_index + 5] - sf [coef_index + 7];\r
+\r
+ const flt_t vr = sf [coef_index + 1] - sf [coef_index + 3];\r
+ const flt_t vi = sf [coef_index + 5] + sf [coef_index + 7];\r
+\r
+ df [coef_index + 5] = (vr + vi) * sqrt2_2;\r
+ df [coef_index + 7] = (vi - vr) * sqrt2_2;\r
+\r
+ coef_index += 8;\r
+ }\r
+ while (coef_index < _length);\r
+ }\r
+\r
+ /* Penultimate and last pass at once */\r
+ {\r
+ coef_index = 0;\r
+ const long * bit_rev_lut_ptr = _bit_rev_lut.get_ptr ();\r
+ const flt_t * sf2 = df;\r
+ do\r
+ {\r
+ {\r
+ const flt_t b_0 = sf2 [0] + sf2 [2];\r
+ const flt_t b_2 = sf2 [0] - sf2 [2];\r
+ const flt_t b_1 = sf2 [1] * 2;\r
+ const flt_t b_3 = sf2 [3] * 2;\r
+\r
+ x [bit_rev_lut_ptr [0]] = b_0 + b_1;\r
+ x [bit_rev_lut_ptr [1]] = b_0 - b_1;\r
+ x [bit_rev_lut_ptr [2]] = b_2 + b_3;\r
+ x [bit_rev_lut_ptr [3]] = b_2 - b_3;\r
+ }\r
+ {\r
+ const flt_t b_0 = sf2 [4] + sf2 [6];\r
+ const flt_t b_2 = sf2 [4] - sf2 [6];\r
+ const flt_t b_1 = sf2 [5] * 2;\r
+ const flt_t b_3 = sf2 [7] * 2;\r
+\r
+ x [bit_rev_lut_ptr [4]] = b_0 + b_1;\r
+ x [bit_rev_lut_ptr [5]] = b_0 - b_1;\r
+ x [bit_rev_lut_ptr [6]] = b_2 + b_3;\r
+ x [bit_rev_lut_ptr [7]] = b_2 - b_3;\r
+ }\r
+\r
+ sf2 += 8;\r
+ coef_index += 8;\r
+ bit_rev_lut_ptr += 8;\r
+ }\r
+ while (coef_index < _length);\r
+ }\r
+ }\r
+ }\r
+\r
+/*______________________________________________\r
+ *\r
+ * Special cases\r
+ *______________________________________________\r
+ */\r
+\r
+ /* 4-point IFFT */\r
+ else if (_nbr_bits == 2)\r
+ {\r
+ const flt_t b_0 = f [0] + f [2];\r
+ const flt_t b_2 = f [0] - f [2];\r
+\r
+ x [0] = b_0 + f [1] * 2;\r
+ x [2] = b_0 - f [1] * 2;\r
+ x [1] = b_2 + f [3] * 2;\r
+ x [3] = b_2 - f [3] * 2;\r
+ }\r
+\r
+ /* 2-point IFFT */\r
+ else if (_nbr_bits == 1)\r
+ {\r
+ x [0] = f [0] + f [1];\r
+ x [1] = f [0] - f [1];\r
+ }\r
+\r
+ /* 1-point IFFT */\r
+ else\r
+ {\r
+ x [0] = f [0];\r
+ }\r
+}\r
+\r
+\r
+\r
+/*==========================================================================*/\r
+/* Name: rescale */\r
+/* Description: Scale an array by divide each element by its length. */\r
+/* This function should be called after FFT + IFFT. */\r
+/* Input/Output parameters: */\r
+/* - x: pointer on array to rescale (time or frequency). */\r
+/* Throws: Nothing */\r
+/*==========================================================================*/\r
+\r
+void FFTReal::rescale (flt_t x []) const\r
+{\r
+ const flt_t mul = flt_t (1.0 / _length);\r
+ long i = _length - 1;\r
+\r
+ do\r
+ {\r
+ x [i] *= mul;\r
+ --i;\r
+ }\r
+ while (i >= 0);\r
+}\r
+\r
+\r
+\r
+/*\\\ NESTED CLASS MEMBER FUNCTIONS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/\r
+\r
+\r
+\r
+/*==========================================================================*/\r
+/* Name: Constructor */\r
+/* Input parameters: */\r
+/* - nbr_bits: number of bits of the array on which we want to do a */\r
+/* FFT. Range: > 0 */\r
+/* Throws: std::bad_alloc */\r
+/*==========================================================================*/\r
+\r
+FFTReal::BitReversedLUT::BitReversedLUT (const int nbr_bits)\r
+{\r
+ long length;\r
+ long cnt;\r
+ long br_index;\r
+ long bit;\r
+\r
+ length = 1L << nbr_bits;\r
+ _ptr = new long [length];\r
+\r
+ br_index = 0;\r
+ _ptr [0] = 0;\r
+ for (cnt = 1; cnt < length; ++cnt)\r
+ {\r
+ /* ++br_index (bit reversed) */\r
+ bit = length >> 1;\r
+ while (((br_index ^= bit) & bit) == 0)\r
+ {\r
+ bit >>= 1;\r
+ }\r
+\r
+ _ptr [cnt] = br_index;\r
+ }\r
+}\r
+\r
+\r
+\r
+/*==========================================================================*/\r
+/* Name: Destructor */\r
+/*==========================================================================*/\r
+\r
+FFTReal::BitReversedLUT::~BitReversedLUT (void)\r
+{\r
+ delete [] _ptr;\r
+ _ptr = 0;\r
+}\r
+\r
+\r
+\r
+/*==========================================================================*/\r
+/* Name: Constructor */\r
+/* Input parameters: */\r
+/* - nbr_bits: number of bits of the array on which we want to do a */\r
+/* FFT. Range: > 0 */\r
+/* Throws: std::bad_alloc, anything */\r
+/*==========================================================================*/\r
+\r
+FFTReal::TrigoLUT::TrigoLUT (const int nbr_bits)\r
+{\r
+ long total_len;\r
+\r
+ _ptr = 0;\r
+ if (nbr_bits > 3)\r
+ {\r
+ total_len = (1L << (nbr_bits - 1)) - 4;\r
+ _ptr = new flt_t [total_len];\r
+\r
+ const double PI = atan (1) * 4;\r
+ for (int level = 3; level < nbr_bits; ++level)\r
+ {\r
+ const long level_len = 1L << (level - 1);\r
+ flt_t * const level_ptr = const_cast<flt_t *> (get_ptr (level));\r
+ const double mul = PI / (level_len << 1);\r
+\r
+ for (long i = 0; i < level_len; ++ i)\r
+ {\r
+ level_ptr [i] = (flt_t) cos (i * mul);\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+\r
+\r
+/*==========================================================================*/\r
+/* Name: Destructor */\r
+/*==========================================================================*/\r
+\r
+FFTReal::TrigoLUT::~TrigoLUT (void)\r
+{\r
+ delete [] _ptr;\r
+ _ptr = 0;\r
+}\r
+\r
+\r
+\r
+#if defined (_MSC_VER)\r
+#pragma pack (pop)\r
+#endif // _MSC_VER\r
+\r
+\r
+\r
+/*****************************************************************************\r
+\r
+ LEGAL\r
+\r
+ Source code may be freely used for any purpose, including commercial\r
+ applications. Programs must display in their "About" dialog-box (or\r
+ documentation) a text telling they use these routines by Laurent de Soras.\r
+ Modified source code can be distributed, but modifications must be clearly\r
+ indicated.\r
+\r
+ CONTACT\r
+\r
+ Laurent de Soras\r
+ 92 avenue Albert 1er\r
+ 92500 Rueil-Malmaison\r
+ France\r
+\r
+ ldesoras@club-internet.fr\r
+\r
+*****************************************************************************/\r
+\r
+\r
+\r
+/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/\r
--- /dev/null
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * mod_stress.cpp -- Detect Voice Stress
+ *
+ */
+
+#include <stdexcept>
+#include <stdio.h>
+#include "FFTReal.h"
+using namespace std;
+
+#include <switch.h>
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_stress_load);
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_stress_shutdown);
+SWITCH_MODULE_DEFINITION(mod_stress, mod_stress_load, mod_stress_shutdown, NULL);
+
+struct stress_helper {
+ switch_core_session_t *session;
+ int read;
+ uint32_t frame_size;
+ FFTReal *fft;
+ float *data;
+ float *result;
+ float *pow_spectrum;
+ float bind;
+ int start;
+ int end;
+ float avg_tremor_pwr;
+ float avg_total_pwr;
+ float total_pwr;
+ float tremor_ratio;
+ float stress;
+ uint32_t rate;
+ switch_buffer_t *audio_buffer;
+ int16_t *audio;
+};
+
+static switch_bool_t stress_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
+{
+ struct stress_helper *sth = (struct stress_helper *) user_data;
+
+ switch (type) {
+ case SWITCH_ABC_TYPE_INIT:
+ {
+ switch_codec_t *read_codec = switch_core_session_get_read_codec(sth->session);
+
+ sth->rate = read_codec->implementation->actual_samples_per_second;
+
+ if (sth->rate == 8000) {
+ sth->frame_size = 8192;
+ } else if (sth->rate == 16000) {
+ sth->frame_size = 16384;
+ } else if (sth->rate == 32000) {
+ sth->frame_size = 32768;
+ } else {
+ return SWITCH_FALSE;
+ }
+
+ sth->data = (float *) switch_core_session_alloc(sth->session, sizeof(*sth->data) * sth->frame_size);
+ sth->result = (float *) switch_core_session_alloc(sth->session, sizeof(*sth->result) * sth->frame_size);
+ sth->pow_spectrum = (float *) switch_core_session_alloc(sth->session, sizeof(*sth->pow_spectrum) * sth->frame_size);
+ sth->audio = (int16_t *) switch_core_session_alloc(sth->session, sizeof(*sth->audio) * sth->frame_size);
+
+ sth->fft = new FFTReal (sth->frame_size);
+ switch_buffer_create_dynamic(&sth->audio_buffer, sth->frame_size, sth->frame_size * 3, 0);
+
+ sth->bind = (float) sth->rate / sth->frame_size;
+ sth->start = (int) (8.0 / sth->bind);
+ sth->end = (int) (14.0 / sth->bind);
+
+ }
+ break;
+ case SWITCH_ABC_TYPE_CLOSE:
+ {
+ switch_buffer_destroy(&sth->audio_buffer);
+ delete sth->fft;
+ }
+ break;
+ case SWITCH_ABC_TYPE_READ:
+ case SWITCH_ABC_TYPE_WRITE:
+ break;
+ case SWITCH_ABC_TYPE_READ_REPLACE:
+ case SWITCH_ABC_TYPE_WRITE_REPLACE:
+ {
+ switch_frame_t *frame;
+
+ if (sth->read) {
+ frame = switch_core_media_bug_get_read_replace_frame(bug);
+ } else {
+ frame = switch_core_media_bug_get_write_replace_frame(bug);
+ }
+
+ if (!switch_test_flag(frame, SFF_CNG)) {
+ switch_buffer_write(sth->audio_buffer, frame->data, frame->datalen);
+ }
+
+ sth->stress = 0.0;
+
+ if (switch_buffer_inuse(sth->audio_buffer) >= sth->frame_size * sizeof(int16_t)) {
+ switch_size_t bytes;
+ uint32_t samples, i;
+ const float threshold = 1.5;
+
+ bytes = switch_buffer_read(sth->audio_buffer, sth->audio, sth->frame_size * sizeof(int16_t));
+ samples = bytes / sizeof(int16_t);
+
+ switch_short_to_float(sth->audio, sth->data, samples);
+ sth->fft->do_fft(sth->result, sth->data);
+
+ for (i = 0; i < samples; ++i) {
+ sth->pow_spectrum[i] = pow(fabs(sth->result[i]), 2) / (float) samples;
+ }
+
+ sth->avg_tremor_pwr = 0.0;
+ sth->avg_total_pwr = 0.0;
+ sth->total_pwr = 0.0;
+
+ for (i = sth->start; i <= sth->end; ++i) {
+ sth->avg_tremor_pwr += sth->pow_spectrum[i];
+ }
+ sth->avg_tremor_pwr /= ((sth->end - sth->start) + 1);
+
+ for (i = 0; i < samples; ++i) {
+ sth->total_pwr += sth->pow_spectrum[i];
+ }
+ sth->avg_total_pwr = sth->total_pwr / samples;
+
+ if (sth->total_pwr < threshold) {
+ sth->tremor_ratio = 0.0;
+ } else {
+ sth->tremor_ratio = sth->avg_tremor_pwr / sth->avg_total_pwr;
+ }
+
+ if (sth->total_pwr >= 1.0) {
+ float d = pow(sth->tremor_ratio, 4);
+ if (d > 0.0) {
+ sth->stress = (10.0 / d) / 10000;
+ if (sth->stress >= 20000.0) {
+ sth->stress = 20000.0;
+ }
+ }
+ }
+ }
+
+ if (sth->stress) {
+ switch_event_t *event, *dup;
+
+ if (switch_event_create(&event, SWITCH_EVENT_DETECTED_SPEECH) == SWITCH_STATUS_SUCCESS) {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Speech-Type", "stress-level");
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Stress-Level", "%02f", sth->stress);
+ if (switch_event_dup(&dup, event) == SWITCH_STATUS_SUCCESS) {
+ switch_event_fire(&dup);
+ }
+ if (switch_core_session_queue_event(sth->session, &event) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Event queue failed!\n");
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "delivery-failure", "true");
+ switch_event_fire(&event);
+ }
+ }
+ }
+ }
+ default:
+ break;
+ }
+
+ return SWITCH_TRUE;
+}
+
+SWITCH_STANDARD_APP(stress_start_function)
+{
+ switch_media_bug_t *bug;
+ switch_status_t status;
+ switch_channel_t *channel = switch_core_session_get_channel(session);
+ struct stress_helper *sth;
+ char *argv[6];
+ int argc;
+ char *lbuf = NULL;
+ int x = 0;
+
+ if ((bug = (switch_media_bug_t *) switch_channel_get_private(channel, "_stress_"))) {
+ if (!switch_strlen_zero(data) && !strcasecmp(data, "stop")) {
+ switch_channel_set_private(channel, "_stress_", NULL);
+ switch_core_media_bug_remove(session, &bug);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot run 2 at once on the same channel!\n");
+ }
+ return;
+ }
+
+ sth = (struct stress_helper *) switch_core_session_alloc(session, sizeof(*sth));
+ assert(sth != NULL);
+
+
+ if (data && (lbuf = switch_core_session_strdup(session, data))
+ && (argc = switch_separate_string(lbuf, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) {
+ if (!strncasecmp(argv[x], "read", 4)) {
+ sth->read = 1;
+ }
+ }
+
+ sth->session = session;
+
+ if ((status = switch_core_media_bug_add(session, stress_callback, sth, 0,
+ sth->read ? SMBF_READ_REPLACE : SMBF_WRITE_REPLACE, &bug)) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failure!\n");
+ return;
+ }
+
+ switch_channel_set_private(channel, "_stress_", bug);
+
+}
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_stress_load)
+{
+ switch_application_interface_t *app_interface;
+
+ *module_interface = switch_loadable_module_create_module_interface(pool, modname);
+
+ SWITCH_ADD_APP(app_interface, "stress", "Analyze the stream for voice stress", "Analyze the stream for voice stress",
+ stress_start_function, "[read|write|stop]", SAF_NONE);
+
+ /* indicate that the module should continue to be loaded */
+ return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_stress_shutdown)
+{
+ return SWITCH_STATUS_UNLOAD;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:nil
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
+ */