SphinxBase 0.6
|
00001 /* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */ 00002 /* ==================================================================== 00003 * Copyright (c) 2006 Carnegie Mellon University. All rights 00004 * reserved. 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions 00008 * are met: 00009 * 00010 * 1. Redistributions of source code must retain the above copyright 00011 * notice, this list of conditions and the following disclaimer. 00012 * 00013 * 2. Redistributions in binary form must reproduce the above copyright 00014 * notice, this list of conditions and the following disclaimer in 00015 * the documentation and/or other materials provided with the 00016 * distribution. 00017 * 00018 * This work was supported in part by funding from the Defense Advanced 00019 * Research Projects Agency and the National Science Foundation of the 00020 * United States of America, and the CMU Sphinx Speech Consortium. 00021 * 00022 * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND 00023 * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 00024 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 00025 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY 00026 * NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00027 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 00028 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 00029 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 00030 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00031 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 00032 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00033 * 00034 * ==================================================================== 00035 * 00036 */ 00037 /********************************************************************* 00038 * 00039 * File: fe_warp_piecewise_linear.c 00040 * 00041 * Description: 00042 * 00043 * Warp the frequency axis according to an piecewise linear 00044 * function. The function is linear up to a frequency F, where 00045 * the slope changes so that the Nyquist frequency in the warped 00046 * axis maps to the Nyquist frequency in the unwarped. 00047 * 00048 * w' = a * w, w < F 00049 * w' = a' * w + b, W > F 00050 * w'(0) = 0 00051 * w'(F) = F 00052 * w'(Nyq) = Nyq 00053 * 00054 *********************************************************************/ 00055 00056 /* static char rcsid[] = "@(#)$Id: fe_warp_piecewise_linear.c,v 1.2 2006/02/17 00:31:34 egouvea Exp $"; */ 00057 00058 #include <stdio.h> 00059 #include <stdlib.h> 00060 #include <math.h> 00061 #include <string.h> 00062 00063 #ifdef _MSC_VER 00064 #pragma warning (disable: 4996) 00065 #endif 00066 00067 #include "sphinxbase/strfuncs.h" 00068 #include "sphinxbase/err.h" 00069 00070 #include "fe_warp.h" 00071 #include "fe_warp_piecewise_linear.h" 00072 00073 #define N_PARAM 2 00074 #define YES 1 00075 #define NO 0 00076 00077 /* 00078 * params[0] : a 00079 * params[1] : F (the non-differentiable point) 00080 */ 00081 static float params[N_PARAM] = { 1.0f, 6800.0f }; 00082 static float final_piece[2]; 00083 static int32 is_neutral = YES; 00084 static char p_str[256] = ""; 00085 static float nyquist_frequency = 0.0f; 00086 00087 00088 const char * 00089 fe_warp_piecewise_linear_doc() 00090 { 00091 return "piecewise_linear :== < w' = a * w, w < F >"; 00092 } 00093 00094 uint32 00095 fe_warp_piecewise_linear_id() 00096 { 00097 return FE_WARP_ID_PIECEWISE_LINEAR; 00098 } 00099 00100 uint32 00101 fe_warp_piecewise_linear_n_param() 00102 { 00103 return N_PARAM; 00104 } 00105 00106 void 00107 fe_warp_piecewise_linear_set_parameters(char const *param_str, 00108 float sampling_rate) 00109 { 00110 char *tok; 00111 char *seps = " \t"; 00112 char temp_param_str[256]; 00113 int param_index = 0; 00114 00115 nyquist_frequency = sampling_rate / 2; 00116 if (param_str == NULL) { 00117 is_neutral = YES; 00118 return; 00119 } 00120 /* The new parameters are the same as the current ones, so do nothing. */ 00121 if (strcmp(param_str, p_str) == 0) { 00122 return; 00123 } 00124 is_neutral = NO; 00125 strcpy(temp_param_str, param_str); 00126 memset(params, 0, N_PARAM * sizeof(float)); 00127 memset(final_piece, 0, 2 * sizeof(float)); 00128 strcpy(p_str, param_str); 00129 /* FIXME: strtok() is not re-entrant... */ 00130 tok = strtok(temp_param_str, seps); 00131 while (tok != NULL) { 00132 params[param_index++] = (float) atof_c(tok); 00133 tok = strtok(NULL, seps); 00134 if (param_index >= N_PARAM) { 00135 break; 00136 } 00137 } 00138 if (tok != NULL) { 00139 E_INFO 00140 ("Piecewise linear warping takes up to two arguments, %s ignored.\n", 00141 tok); 00142 } 00143 if (params[1] < sampling_rate) { 00144 /* Precompute these. These are the coefficients of a 00145 * straight line that contains the points (F, aF) and (N, 00146 * N), where a = params[0], F = params[1], N = Nyquist 00147 * frequency. 00148 */ 00149 if (params[1] == 0) { 00150 params[1] = sampling_rate * 0.85f; 00151 } 00152 final_piece[0] = 00153 (nyquist_frequency - 00154 params[0] * params[1]) / (nyquist_frequency - params[1]); 00155 final_piece[1] = 00156 nyquist_frequency * params[1] * (params[0] - 00157 1.0f) / (nyquist_frequency - 00158 params[1]); 00159 } 00160 else { 00161 memset(final_piece, 0, 2 * sizeof(float)); 00162 } 00163 if (params[0] == 0) { 00164 is_neutral = YES; 00165 E_INFO 00166 ("Piecewise linear warping cannot have slope zero, warping not applied.\n"); 00167 } 00168 } 00169 00170 float 00171 fe_warp_piecewise_linear_warped_to_unwarped(float nonlinear) 00172 { 00173 if (is_neutral) { 00174 return nonlinear; 00175 } 00176 else { 00177 /* linear = (nonlinear - b) / a */ 00178 float temp; 00179 if (nonlinear < params[0] * params[1]) { 00180 temp = nonlinear / params[0]; 00181 } 00182 else { 00183 temp = nonlinear - final_piece[1]; 00184 temp /= final_piece[0]; 00185 } 00186 if (temp > nyquist_frequency) { 00187 E_WARN 00188 ("Warp factor %g results in frequency (%.1f) higher than Nyquist (%.1f)\n", 00189 params[0], temp, nyquist_frequency); 00190 } 00191 return temp; 00192 } 00193 } 00194 00195 float 00196 fe_warp_piecewise_linear_unwarped_to_warped(float linear) 00197 { 00198 if (is_neutral) { 00199 return linear; 00200 } 00201 else { 00202 float temp; 00203 /* nonlinear = a * linear - b */ 00204 if (linear < params[1]) { 00205 temp = linear * params[0]; 00206 } 00207 else { 00208 temp = final_piece[0] * linear + final_piece[1]; 00209 } 00210 return temp; 00211 } 00212 } 00213 00214 void 00215 fe_warp_piecewise_linear_print(const char *label) 00216 { 00217 uint32 i; 00218 00219 for (i = 0; i < N_PARAM; i++) { 00220 printf("%s[%04u]: %6.3f ", label, i, params[i]); 00221 } 00222 printf("\n"); 00223 } 00224 00225 /* 00226 * Log record. Maintained by RCS. 00227 * 00228 * $Log: fe_warp_piecewise_linear.c,v $ 00229 * Revision 1.2 2006/02/17 00:31:34 egouvea 00230 * Removed switch -melwarp. Changed the default for window length to 00231 * 0.025625 from 0.256 (so that a window at 16kHz sampling rate has 00232 * exactly 410 samples). Cleaned up include's. Replaced some E_FATAL() 00233 * with E_WARN() and return. 00234 * 00235 * Revision 1.1 2006/02/16 00:18:26 egouvea 00236 * Implemented flexible warping function. The user can specify at run 00237 * time which of several shapes they want to use. Currently implemented 00238 * are an affine function (y = ax + b), an inverse linear (y = a/x) and a 00239 * piecewise linear (y = ax, up to a frequency F, and then it "breaks" so 00240 * Nyquist frequency matches in both scales. 00241 * 00242 * Added two switches, -warp_type and -warp_params. The first specifies 00243 * the type, which valid values: 00244 * 00245 * -inverse or inverse_linear 00246 * -linear or affine 00247 * -piecewise or piecewise_linear 00248 * 00249 * The inverse_linear is the same as implemented by EHT. The -mel_warp 00250 * switch was kept for compatibility (maybe remove it in the 00251 * future?). The code is compatible with EHT's changes: cepstra created 00252 * from code after his changes should be the same as now. Scripts that 00253 * worked with his changes should work now without changes. Tested a few 00254 * cases, same results. 00255 * 00256 */