1 /* 2 ** Copyright (c) 2002-2016, 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/erikd/libsamplerate/blob/master/COPYING 7 */ 8 9 #include "precomp.h" 10 11 static int linear_vari_process (SRC_PRIVATE *psrc, SRC_DATA *data) ; 12 static void linear_reset (SRC_PRIVATE *psrc) ; 13 14 /*======================================================================================== 15 */ 16 17 #define LINEAR_MAGIC_MARKER MAKE_MAGIC ('l', 'i', 'n', 'e', 'a', 'r') 18 19 #define SRC_DEBUG 0 20 21 typedef struct 22 { int linear_magic_marker ; 23 int channels ; 24 int reset ; 25 long in_count, in_used ; 26 long out_count, out_gen ; 27 float last_value [1] ; 28 } LINEAR_DATA ; 29 30 /*---------------------------------------------------------------------------------------- 31 */ 32 33 static int 34 linear_vari_process (SRC_PRIVATE *psrc, SRC_DATA *data) 35 { LINEAR_DATA *priv ; 36 double src_ratio, input_index, rem ; 37 int ch ; 38 39 if (data->input_frames <= 0) 40 return SRC_ERR_NO_ERROR ; 41 42 if (psrc->private_data == NULL) 43 return SRC_ERR_NO_PRIVATE ; 44 45 priv = (LINEAR_DATA*) psrc->private_data ; 46 47 if (priv->reset) 48 { /* If we have just been reset, set the last_value data. */ 49 for (ch = 0 ; ch < priv->channels ; ch++) 50 priv->last_value [ch] = data->data_in [ch] ; 51 priv->reset = 0 ; 52 } ; 53 54 priv->in_count = data->input_frames * priv->channels ; 55 priv->out_count = data->output_frames * priv->channels ; 56 priv->in_used = priv->out_gen = 0 ; 57 58 src_ratio = psrc->last_ratio ; 59 60 if (is_bad_src_ratio (src_ratio)) 61 return SRC_ERR_BAD_INTERNAL_STATE ; 62 63 input_index = psrc->last_position ; 64 65 /* Calculate samples before first sample in input array. */ 66 while (input_index < 1.0 && priv->out_gen < priv->out_count) 67 { 68 if (priv->in_used + priv->channels * (1.0 + input_index) >= priv->in_count) 69 break ; 70 71 if (priv->out_count > 0 && fabs (psrc->last_ratio - data->src_ratio) > SRC_MIN_RATIO_DIFF) 72 src_ratio = psrc->last_ratio + priv->out_gen * (data->src_ratio - psrc->last_ratio) / priv->out_count ; 73 74 for (ch = 0 ; ch < priv->channels ; ch++) 75 { data->data_out [priv->out_gen] = (float) (priv->last_value [ch] + input_index * 76 (data->data_in [ch] - priv->last_value [ch])) ; 77 priv->out_gen ++ ; 78 } ; 79 80 /* Figure out the next index. */ 81 input_index += 1.0 / src_ratio ; 82 } ; 83 84 rem = fmod_one (input_index) ; 85 priv->in_used += priv->channels * lrint (input_index - rem) ; 86 input_index = rem ; 87 88 /* Main processing loop. */ 89 while (priv->out_gen < priv->out_count && priv->in_used + priv->channels * input_index < priv->in_count) 90 { 91 if (priv->out_count > 0 && fabs (psrc->last_ratio - data->src_ratio) > SRC_MIN_RATIO_DIFF) 92 src_ratio = psrc->last_ratio + priv->out_gen * (data->src_ratio - psrc->last_ratio) / priv->out_count ; 93 94 if (SRC_DEBUG && priv->in_used < priv->channels && input_index < 1.0) 95 { printf ("Whoops!!!! in_used : %ld channels : %d input_index : %f\n", priv->in_used, priv->channels, input_index) ; 96 exit (1) ; 97 } ; 98 99 for (ch = 0 ; ch < priv->channels ; ch++) 100 { data->data_out [priv->out_gen] = (float) (data->data_in [priv->in_used - priv->channels + ch] + input_index * 101 (data->data_in [priv->in_used + ch] - data->data_in [priv->in_used - priv->channels + ch])) ; 102 priv->out_gen ++ ; 103 } ; 104 105 /* Figure out the next index. */ 106 input_index += 1.0 / src_ratio ; 107 rem = fmod_one (input_index) ; 108 109 priv->in_used += priv->channels * lrint (input_index - rem) ; 110 input_index = rem ; 111 } ; 112 113 if (priv->in_used > priv->in_count) 114 { input_index += (priv->in_used - priv->in_count) / priv->channels ; 115 priv->in_used = priv->in_count ; 116 } ; 117 118 psrc->last_position = input_index ; 119 120 if (priv->in_used > 0) 121 for (ch = 0 ; ch < priv->channels ; ch++) 122 priv->last_value [ch] = data->data_in [priv->in_used - priv->channels + ch] ; 123 124 /* Save current ratio rather then target ratio. */ 125 psrc->last_ratio = src_ratio ; 126 127 data->input_frames_used = priv->in_used / priv->channels ; 128 data->output_frames_gen = priv->out_gen / priv->channels ; 129 130 return SRC_ERR_NO_ERROR ; 131 } /* linear_vari_process */ 132 133 /*------------------------------------------------------------------------------ 134 */ 135 136 const char* 137 linear_get_name (int src_enum) 138 { 139 if (src_enum == SRC_LINEAR) 140 return "Linear Interpolator" ; 141 142 return NULL ; 143 } /* linear_get_name */ 144 145 const char* 146 linear_get_description (int src_enum) 147 { 148 if (src_enum == SRC_LINEAR) 149 return "Linear interpolator, very fast, poor quality." ; 150 151 return NULL ; 152 } /* linear_get_descrition */ 153 154 int 155 linear_set_converter (SRC_PRIVATE *psrc, int src_enum) 156 { LINEAR_DATA *priv = NULL ; 157 158 if (src_enum != SRC_LINEAR) 159 return SRC_ERR_BAD_CONVERTER ; 160 161 if (psrc->private_data != NULL) 162 { free (psrc->private_data) ; 163 psrc->private_data = NULL ; 164 } ; 165 166 if (psrc->private_data == NULL) 167 { priv = calloc (1, sizeof (*priv) + psrc->channels * sizeof (float)) ; 168 psrc->private_data = priv ; 169 } ; 170 171 if (priv == NULL) 172 return SRC_ERR_MALLOC_FAILED ; 173 174 priv->linear_magic_marker = LINEAR_MAGIC_MARKER ; 175 priv->channels = psrc->channels ; 176 177 psrc->const_process = linear_vari_process ; 178 psrc->vari_process = linear_vari_process ; 179 psrc->reset = linear_reset ; 180 181 linear_reset (psrc) ; 182 183 return SRC_ERR_NO_ERROR ; 184 } /* linear_set_converter */ 185 186 /*=================================================================================== 187 */ 188 189 static void 190 linear_reset (SRC_PRIVATE *psrc) 191 { LINEAR_DATA *priv = NULL ; 192 193 priv = (LINEAR_DATA*) psrc->private_data ; 194 if (priv == NULL) 195 return ; 196 197 priv->channels = psrc->channels ; 198 priv->reset = 1 ; 199 memset (priv->last_value, 0, sizeof (priv->last_value [0]) * priv->channels) ; 200 201 return ; 202 } /* linear_reset */ 203 204