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 * 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 *
zoh_data_new(int channels)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 *
zoh_state_new(int channels,SRC_ERROR * error)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
zoh_reset(SRC_STATE * state)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 *
zoh_copy(SRC_STATE * 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
zoh_close(SRC_STATE * state)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