Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/libsamplerate/src_zoh.c
39476 views
1
/*
2
** Copyright (c) 2002-2021, Erik de Castro Lopo <[email protected]>
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
294