1 /* 2 ** Copyright (c) 2002-2021, Erik de Castro Lopo <erikd@mega-nerd.com> 3 ** All rights reserved. 4 ** 5 ** This code is released under 2-clause BSD license. Please see the 6 ** file at : https://github.com/libsndfile/libsamplerate/blob/master/COPYING 7 */ 8 9 #ifdef HAVE_CONFIG_H 10 #include "config.h" 11 #endif 12 13 #include <assert.h> 14 #include <stdio.h> 15 #include <stdlib.h> 16 #include <string.h> 17 #include <math.h> 18 19 #include "common.h" 20 21 static SRC_ERROR zoh_vari_process (SRC_STATE *state, SRC_DATA *data) ; 22 static void zoh_reset (SRC_STATE *state) ; 23 static SRC_STATE *zoh_copy (SRC_STATE *state) ; 24 static void zoh_close (SRC_STATE *state) ; 25 26 /*======================================================================================== 27 */ 28 29 #define ZOH_MAGIC_MARKER MAKE_MAGIC ('s', 'r', 'c', 'z', 'o', 'h') 30 31 typedef struct 32 { int zoh_magic_marker ; 33 bool dirty ; 34 long in_count, in_used ; 35 long out_count, out_gen ; 36 float *last_value ; 37 } ZOH_DATA ; 38 39 static SRC_STATE_VT zoh_state_vt = 40 { 41 zoh_vari_process, 42 zoh_vari_process, 43 zoh_reset, 44 zoh_copy, 45 zoh_close 46 } ; 47 48 /*---------------------------------------------------------------------------------------- 49 */ 50 51 static SRC_ERROR 52 zoh_vari_process (SRC_STATE *state, SRC_DATA *data) 53 { ZOH_DATA *priv ; 54 double src_ratio, input_index, rem ; 55 int ch ; 56 57 if (data->input_frames <= 0) 58 return SRC_ERR_NO_ERROR ; 59 60 if (state->private_data == NULL) 61 return SRC_ERR_NO_PRIVATE ; 62 63 priv = (ZOH_DATA*) state->private_data ; 64 65 if (!priv->dirty) 66 { /* If we have just been reset, set the last_value data. */ 67 for (ch = 0 ; ch < state->channels ; ch++) 68 priv->last_value [ch] = data->data_in [ch] ; 69 priv->dirty = true ; 70 } ; 71 72 priv->in_count = data->input_frames * state->channels ; 73 priv->out_count = data->output_frames * state->channels ; 74 priv->in_used = priv->out_gen = 0 ; 75 76 src_ratio = state->last_ratio ; 77 78 if (is_bad_src_ratio (src_ratio)) 79 return SRC_ERR_BAD_INTERNAL_STATE ; 80 81 input_index = state->last_position ; 82 83 /* Calculate samples before first sample in input array. */ 84 while (input_index < 1.0 && priv->out_gen < priv->out_count) 85 { 86 if (priv->in_used + state->channels * input_index >= priv->in_count) 87 break ; 88 89 if (priv->out_count > 0 && fabs (state->last_ratio - data->src_ratio) > SRC_MIN_RATIO_DIFF) 90 src_ratio = state->last_ratio + priv->out_gen * (data->src_ratio - state->last_ratio) / priv->out_count ; 91 92 for (ch = 0 ; ch < state->channels ; ch++) 93 { data->data_out [priv->out_gen] = priv->last_value [ch] ; 94 priv->out_gen ++ ; 95 } ; 96 97 /* Figure out the next index. */ 98 input_index += 1.0 / src_ratio ; 99 } ; 100 101 rem = fmod_one (input_index) ; 102 priv->in_used += state->channels * lrint (input_index - rem) ; 103 input_index = rem ; 104 105 /* Main processing loop. */ 106 while (priv->out_gen < priv->out_count && priv->in_used + state->channels * input_index <= priv->in_count) 107 { 108 if (priv->out_count > 0 && fabs (state->last_ratio - data->src_ratio) > SRC_MIN_RATIO_DIFF) 109 src_ratio = state->last_ratio + priv->out_gen * (data->src_ratio - state->last_ratio) / priv->out_count ; 110 111 for (ch = 0 ; ch < state->channels ; ch++) 112 { data->data_out [priv->out_gen] = data->data_in [priv->in_used - state->channels + ch] ; 113 priv->out_gen ++ ; 114 } ; 115 116 /* Figure out the next index. */ 117 input_index += 1.0 / src_ratio ; 118 rem = fmod_one (input_index) ; 119 120 priv->in_used += state->channels * lrint (input_index - rem) ; 121 input_index = rem ; 122 } ; 123 124 if (priv->in_used > priv->in_count) 125 { input_index += (priv->in_used - priv->in_count) / state->channels ; 126 priv->in_used = priv->in_count ; 127 } ; 128 129 state->last_position = input_index ; 130 131 if (priv->in_used > 0) 132 for (ch = 0 ; ch < state->channels ; ch++) 133 priv->last_value [ch] = data->data_in [priv->in_used - state->channels + ch] ; 134 135 /* Save current ratio rather then target ratio. */ 136 state->last_ratio = src_ratio ; 137 138 data->input_frames_used = priv->in_used / state->channels ; 139 data->output_frames_gen = priv->out_gen / state->channels ; 140 141 return SRC_ERR_NO_ERROR ; 142 } /* zoh_vari_process */ 143 144 /*------------------------------------------------------------------------------ 145 */ 146 147 #if 0 148 LIBSAMPLERATE_DLL_PRIVATE const char* 149 zoh_get_name (int src_enum) 150 { 151 if (src_enum == SRC_ZERO_ORDER_HOLD) 152 return "ZOH Interpolator" ; 153 154 return NULL ; 155 } /* zoh_get_name */ 156 157 LIBSAMPLERATE_DLL_PRIVATE const char* 158 zoh_get_description (int src_enum) 159 { 160 if (src_enum == SRC_ZERO_ORDER_HOLD) 161 return "Zero order hold interpolator, very fast, poor quality." ; 162 163 return NULL ; 164 } /* zoh_get_descrition */ 165 #endif 166 167 static ZOH_DATA * 168 zoh_data_new (int channels) 169 { 170 assert (channels > 0) ; 171 172 ZOH_DATA *priv = (ZOH_DATA *) calloc (1, sizeof (ZOH_DATA)) ; 173 if (priv) 174 { 175 priv->zoh_magic_marker = ZOH_MAGIC_MARKER ; 176 priv->last_value = (float *) calloc (channels, sizeof (float)) ; 177 if (!priv->last_value) 178 { 179 free (priv) ; 180 priv = NULL ; 181 } 182 } 183 184 return priv ; 185 } 186 187 LIBSAMPLERATE_DLL_PRIVATE SRC_STATE * 188 zoh_state_new (int channels, SRC_ERROR *error) 189 { 190 assert (channels > 0) ; 191 assert (error != NULL) ; 192 193 SRC_STATE *state = (SRC_STATE *) calloc (1, sizeof (SRC_STATE)) ; 194 if (!state) 195 { 196 *error = SRC_ERR_MALLOC_FAILED ; 197 return NULL ; 198 } 199 200 state->channels = channels ; 201 state->mode = SRC_MODE_PROCESS ; 202 203 state->private_data = zoh_data_new (state->channels) ; 204 if (!state->private_data) 205 { 206 free (state) ; 207 *error = SRC_ERR_MALLOC_FAILED ; 208 return NULL ; 209 } 210 211 state->vt = &zoh_state_vt ; 212 213 zoh_reset (state) ; 214 215 *error = SRC_ERR_NO_ERROR ; 216 217 return state ; 218 } 219 220 /*=================================================================================== 221 */ 222 223 static void 224 zoh_reset (SRC_STATE *state) 225 { ZOH_DATA *priv ; 226 227 priv = (ZOH_DATA*) state->private_data ; 228 if (priv == NULL) 229 return ; 230 231 priv->dirty = false ; 232 memset (priv->last_value, 0, sizeof (float) * state->channels) ; 233 234 return ; 235 } /* zoh_reset */ 236 237 static SRC_STATE * 238 zoh_copy (SRC_STATE *state) 239 { 240 assert (state != NULL) ; 241 242 if (state->private_data == NULL) 243 return NULL ; 244 245 SRC_STATE *to = (SRC_STATE *) calloc (1, sizeof (SRC_STATE)) ; 246 if (!to) 247 return NULL ; 248 memcpy (to, state, sizeof (SRC_STATE)) ; 249 250 ZOH_DATA* from_priv = (ZOH_DATA*) state->private_data ; 251 ZOH_DATA *to_priv = (ZOH_DATA *) calloc (1, sizeof (ZOH_DATA)) ; 252 if (!to_priv) 253 { 254 free (to) ; 255 return NULL ; 256 } 257 258 memcpy (to_priv, from_priv, sizeof (ZOH_DATA)) ; 259 to_priv->last_value = (float *) malloc (sizeof (float) * state->channels) ; 260 if (!to_priv->last_value) 261 { 262 free (to) ; 263 free (to_priv) ; 264 return NULL ; 265 } 266 memcpy (to_priv->last_value, from_priv->last_value, sizeof (float) * state->channels) ; 267 268 to->private_data = to_priv ; 269 270 return to ; 271 } /* zoh_copy */ 272 273 static void 274 zoh_close (SRC_STATE *state) 275 { 276 if (state) 277 { 278 ZOH_DATA *zoh = (ZOH_DATA *) state->private_data ; 279 if (zoh) 280 { 281 if (zoh->last_value) 282 { 283 free (zoh->last_value) ; 284 zoh->last_value = NULL ; 285 } 286 free (zoh) ; 287 zoh = NULL ; 288 } 289 free (state) ; 290 state = NULL ; 291 } 292 } /* zoh_close */ 293