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
zoh_vari_process(SRC_STATE * state,SRC_DATA * data)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 * psf_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 * psf_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 LIBSAMPLERATE_DLL_PRIVATE const char*
zoh_get_name(int src_enum)148 zoh_get_name (int src_enum)
149 {
150 if (src_enum == SRC_ZERO_ORDER_HOLD)
151 return "ZOH Interpolator" ;
152
153 return NULL ;
154 } /* zoh_get_name */
155
156 LIBSAMPLERATE_DLL_PRIVATE const char*
zoh_get_description(int src_enum)157 zoh_get_description (int src_enum)
158 {
159 if (src_enum == SRC_ZERO_ORDER_HOLD)
160 return "Zero order hold interpolator, very fast, poor quality." ;
161
162 return NULL ;
163 } /* zoh_get_descrition */
164
165 static ZOH_DATA *
zoh_data_new(int channels)166 zoh_data_new (int channels)
167 {
168 assert (channels > 0) ;
169
170 ZOH_DATA *priv = (ZOH_DATA *) calloc (1, sizeof (ZOH_DATA)) ;
171 if (priv)
172 {
173 priv->zoh_magic_marker = ZOH_MAGIC_MARKER ;
174 priv->last_value = (float *) calloc (channels, sizeof (float)) ;
175 if (!priv->last_value)
176 {
177 free (priv) ;
178 priv = NULL ;
179 }
180 }
181
182 return priv ;
183 }
184
185 LIBSAMPLERATE_DLL_PRIVATE SRC_STATE *
zoh_state_new(int channels,SRC_ERROR * error)186 zoh_state_new (int channels, SRC_ERROR *error)
187 {
188 assert (channels > 0) ;
189 assert (error != NULL) ;
190
191 SRC_STATE *state = (SRC_STATE *) calloc (1, sizeof (SRC_STATE)) ;
192 if (!state)
193 {
194 *error = SRC_ERR_MALLOC_FAILED ;
195 return NULL ;
196 }
197
198 state->channels = channels ;
199 state->mode = SRC_MODE_PROCESS ;
200
201 state->private_data = zoh_data_new (state->channels) ;
202 if (!state->private_data)
203 {
204 free (state) ;
205 *error = SRC_ERR_MALLOC_FAILED ;
206 return NULL ;
207 }
208
209 state->vt = &zoh_state_vt ;
210
211 zoh_reset (state) ;
212
213 *error = SRC_ERR_NO_ERROR ;
214
215 return state ;
216 }
217
218 /*===================================================================================
219 */
220
221 static void
zoh_reset(SRC_STATE * state)222 zoh_reset (SRC_STATE *state)
223 { ZOH_DATA *priv ;
224
225 priv = (ZOH_DATA*) state->private_data ;
226 if (priv == NULL)
227 return ;
228
229 priv->dirty = false ;
230 memset (priv->last_value, 0, sizeof (float) * state->channels) ;
231
232 return ;
233 } /* zoh_reset */
234
235 static SRC_STATE *
zoh_copy(SRC_STATE * state)236 zoh_copy (SRC_STATE *state)
237 {
238 assert (state != NULL) ;
239
240 if (state->private_data == NULL)
241 return NULL ;
242
243 SRC_STATE *to = (SRC_STATE *) calloc (1, sizeof (SRC_STATE)) ;
244 if (!to)
245 return NULL ;
246 memcpy (to, state, sizeof (SRC_STATE)) ;
247
248 ZOH_DATA* from_priv = (ZOH_DATA*) state->private_data ;
249 ZOH_DATA *to_priv = (ZOH_DATA *) calloc (1, sizeof (ZOH_DATA)) ;
250 if (!to_priv)
251 {
252 free (to) ;
253 return NULL ;
254 }
255
256 memcpy (to_priv, from_priv, sizeof (ZOH_DATA)) ;
257 to_priv->last_value = (float *) malloc (sizeof (float) * state->channels) ;
258 if (!to_priv->last_value)
259 {
260 free (to) ;
261 free (to_priv) ;
262 return NULL ;
263 }
264 memcpy (to_priv->last_value, from_priv->last_value, sizeof (float) * state->channels) ;
265
266 to->private_data = to_priv ;
267
268 return to ;
269 } /* zoh_copy */
270
271 static void
zoh_close(SRC_STATE * state)272 zoh_close (SRC_STATE *state)
273 {
274 if (state)
275 {
276 ZOH_DATA *zoh = (ZOH_DATA *) state->private_data ;
277 if (zoh)
278 {
279 if (zoh->last_value)
280 {
281 free (zoh->last_value) ;
282 zoh->last_value = NULL ;
283 }
284 free (zoh) ;
285 zoh = NULL ;
286 }
287 free (state) ;
288 state = NULL ;
289 }
290 } /* zoh_close */
291