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_affine.c 00040 * 00041 * Description: 00042 * Warp the frequency axis according to an affine function, i.e.: 00043 * 00044 * w' = a * w + b 00045 * 00046 *********************************************************************/ 00047 00048 /* static char rcsid[] = "@(#)$Id: fe_warp_affine.c,v 1.2 2006/02/17 00:31:34 egouvea Exp $"; */ 00049 00050 #include <stdio.h> 00051 #include <stdlib.h> 00052 #include <math.h> 00053 #include <string.h> 00054 00055 #ifdef _MSC_VER 00056 #pragma warning (disable: 4996) 00057 #endif 00058 00059 #include "strfuncs.h" 00060 #include "err.h" 00061 #include "fe_warp.h" 00062 #include "fe_warp_affine.h" 00063 00064 #define N_PARAM 2 00065 #define YES 1 00066 #define NO 0 00067 00068 /* 00069 * params[0] : a 00070 * params[1] : b 00071 */ 00072 static float params[N_PARAM] = { 1.0f, 0.0f }; 00073 static int32 is_neutral = YES; 00074 static char p_str[256] = ""; 00075 static float nyquist_frequency = 0.0f; 00076 00077 00078 const char * 00079 fe_warp_affine_doc() 00080 { 00081 return "affine :== < w' = a * x + b >"; 00082 } 00083 00084 uint32 00085 fe_warp_affine_id() 00086 { 00087 return FE_WARP_ID_AFFINE; 00088 } 00089 00090 uint32 00091 fe_warp_affine_n_param() 00092 { 00093 return N_PARAM; 00094 } 00095 00096 void 00097 fe_warp_affine_set_parameters(char const *param_str, float sampling_rate) 00098 { 00099 char *tok; 00100 char *seps = " \t"; 00101 char temp_param_str[256]; 00102 int param_index = 0; 00103 00104 nyquist_frequency = sampling_rate / 2; 00105 if (param_str == NULL) { 00106 is_neutral = YES; 00107 return; 00108 } 00109 /* The new parameters are the same as the current ones, so do nothing. */ 00110 if (strcmp(param_str, p_str) == 0) { 00111 return; 00112 } 00113 is_neutral = NO; 00114 strcpy(temp_param_str, param_str); 00115 memset(params, 0, N_PARAM * sizeof(float)); 00116 strcpy(p_str, param_str); 00117 /* FIXME: strtok() is not re-entrant... */ 00118 tok = strtok(temp_param_str, seps); 00119 while (tok != NULL) { 00120 params[param_index++] = (float) atof_c(tok); 00121 tok = strtok(NULL, seps); 00122 if (param_index >= N_PARAM) { 00123 break; 00124 } 00125 } 00126 if (tok != NULL) { 00127 E_INFO 00128 ("Affine warping takes up to two arguments, %s ignored.\n", 00129 tok); 00130 } 00131 if (params[0] == 0) { 00132 is_neutral = YES; 00133 E_INFO 00134 ("Affine warping cannot have slope zero, warping not applied.\n"); 00135 } 00136 } 00137 00138 float 00139 fe_warp_affine_warped_to_unwarped(float nonlinear) 00140 { 00141 if (is_neutral) { 00142 return nonlinear; 00143 } 00144 else { 00145 /* linear = (nonlinear - b) / a */ 00146 float temp = nonlinear - params[1]; 00147 temp /= params[0]; 00148 if (temp > nyquist_frequency) { 00149 E_WARN 00150 ("Warp factor %g results in frequency (%.1f) higher than Nyquist (%.1f)\n", 00151 params[0], temp, nyquist_frequency); 00152 } 00153 return temp; 00154 } 00155 } 00156 00157 float 00158 fe_warp_affine_unwarped_to_warped(float linear) 00159 { 00160 if (is_neutral) { 00161 return linear; 00162 } 00163 else { 00164 /* nonlinear = a * linear - b */ 00165 float temp = linear * params[0]; 00166 temp += params[1]; 00167 return temp; 00168 } 00169 } 00170 00171 void 00172 fe_warp_affine_print(const char *label) 00173 { 00174 uint32 i; 00175 00176 for (i = 0; i < N_PARAM; i++) { 00177 printf("%s[%04u]: %6.3f ", label, i, params[i]); 00178 } 00179 printf("\n"); 00180 } 00181 00182 /* 00183 * Log record. Maintained by RCS. 00184 * 00185 * $Log: fe_warp_affine.c,v $ 00186 * Revision 1.2 2006/02/17 00:31:34 egouvea 00187 * Removed switch -melwarp. Changed the default for window length to 00188 * 0.025625 from 0.256 (so that a window at 16kHz sampling rate has 00189 * exactly 410 samples). Cleaned up include's. Replaced some E_FATAL() 00190 * with E_WARN() and return. 00191 * 00192 * Revision 1.1 2006/02/16 00:18:26 egouvea 00193 * Implemented flexible warping function. The user can specify at run 00194 * time which of several shapes they want to use. Currently implemented 00195 * are an affine function (y = ax + b), an inverse linear (y = a/x) and a 00196 * piecewise linear (y = ax, up to a frequency F, and then it "breaks" so 00197 * Nyquist frequency matches in both scales. 00198 * 00199 * Added two switches, -warp_type and -warp_params. The first specifies 00200 * the type, which valid values: 00201 * 00202 * -inverse or inverse_linear 00203 * -linear or affine 00204 * -piecewise or piecewise_linear 00205 * 00206 * The inverse_linear is the same as implemented by EHT. The -mel_warp 00207 * switch was kept for compatibility (maybe remove it in the 00208 * future?). The code is compatible with EHT's changes: cepstra created 00209 * from code after his changes should be the same as now. Scripts that 00210 * worked with his changes should work now without changes. Tested a few 00211 * cases, same results. 00212 * 00213 */