• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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