Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/libsamplerate/src_linear.c
39481 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 linear_vari_process (SRC_STATE *state, SRC_DATA *data) ;
22
static void linear_reset (SRC_STATE *state) ;
23
static SRC_STATE *linear_copy (SRC_STATE *state) ;
24
static void linear_close (SRC_STATE *state) ;
25
26
/*========================================================================================
27
*/
28
29
#define LINEAR_MAGIC_MARKER MAKE_MAGIC ('l', 'i', 'n', 'e', 'a', 'r')
30
31
#define SRC_DEBUG 0
32
33
typedef struct
34
{ int linear_magic_marker ;
35
bool dirty ;
36
long in_count, in_used ;
37
long out_count, out_gen ;
38
float *last_value ;
39
} LINEAR_DATA ;
40
41
static SRC_STATE_VT linear_state_vt =
42
{
43
linear_vari_process,
44
linear_vari_process,
45
linear_reset,
46
linear_copy,
47
linear_close
48
} ;
49
50
/*----------------------------------------------------------------------------------------
51
*/
52
53
static SRC_ERROR
54
linear_vari_process (SRC_STATE *state, SRC_DATA *data)
55
{ LINEAR_DATA *priv ;
56
double src_ratio, input_index, rem ;
57
int ch ;
58
59
if (data->input_frames <= 0)
60
return SRC_ERR_NO_ERROR ;
61
62
if (state->private_data == NULL)
63
return SRC_ERR_NO_PRIVATE ;
64
65
priv = (LINEAR_DATA*) state->private_data ;
66
67
if (!priv->dirty)
68
{ /* If we have just been reset, set the last_value data. */
69
for (ch = 0 ; ch < state->channels ; ch++)
70
priv->last_value [ch] = data->data_in [ch] ;
71
priv->dirty = true ;
72
} ;
73
74
priv->in_count = data->input_frames * state->channels ;
75
priv->out_count = data->output_frames * state->channels ;
76
priv->in_used = priv->out_gen = 0 ;
77
78
src_ratio = state->last_ratio ;
79
80
if (is_bad_src_ratio (src_ratio))
81
return SRC_ERR_BAD_INTERNAL_STATE ;
82
83
input_index = state->last_position ;
84
85
/* Calculate samples before first sample in input array. */
86
while (input_index < 1.0 && priv->out_gen < priv->out_count)
87
{
88
if (priv->in_used + state->channels * (1.0 + input_index) >= priv->in_count)
89
break ;
90
91
if (priv->out_count > 0 && fabs (state->last_ratio - data->src_ratio) > SRC_MIN_RATIO_DIFF)
92
src_ratio = state->last_ratio + priv->out_gen * (data->src_ratio - state->last_ratio) / priv->out_count ;
93
94
for (ch = 0 ; ch < state->channels ; ch++)
95
{ data->data_out [priv->out_gen] = (float) (priv->last_value [ch] + input_index *
96
((double) data->data_in [ch] - priv->last_value [ch])) ;
97
priv->out_gen ++ ;
98
} ;
99
100
/* Figure out the next index. */
101
input_index += 1.0 / src_ratio ;
102
} ;
103
104
rem = fmod_one (input_index) ;
105
priv->in_used += state->channels * lrint (input_index - rem) ;
106
input_index = rem ;
107
108
/* Main processing loop. */
109
while (priv->out_gen < priv->out_count && priv->in_used + state->channels * input_index < priv->in_count)
110
{
111
if (priv->out_count > 0 && fabs (state->last_ratio - data->src_ratio) > SRC_MIN_RATIO_DIFF)
112
src_ratio = state->last_ratio + priv->out_gen * (data->src_ratio - state->last_ratio) / priv->out_count ;
113
114
#if SRC_DEBUG
115
if (priv->in_used < state->channels && input_index < 1.0)
116
{ printf ("Whoops!!!! in_used : %ld channels : %d input_index : %f\n", priv->in_used, state->channels, input_index) ;
117
exit (1) ;
118
} ;
119
#endif
120
121
for (ch = 0 ; ch < state->channels ; ch++)
122
{ data->data_out [priv->out_gen] = (float) (data->data_in [priv->in_used - state->channels + ch] + input_index *
123
((double) data->data_in [priv->in_used + ch] - data->data_in [priv->in_used - state->channels + ch])) ;
124
priv->out_gen ++ ;
125
} ;
126
127
/* Figure out the next index. */
128
input_index += 1.0 / src_ratio ;
129
rem = fmod_one (input_index) ;
130
131
priv->in_used += state->channels * lrint (input_index - rem) ;
132
input_index = rem ;
133
} ;
134
135
if (priv->in_used > priv->in_count)
136
{ input_index += (priv->in_used - priv->in_count) / state->channels ;
137
priv->in_used = priv->in_count ;
138
} ;
139
140
state->last_position = input_index ;
141
142
if (priv->in_used > 0)
143
for (ch = 0 ; ch < state->channels ; ch++)
144
priv->last_value [ch] = data->data_in [priv->in_used - state->channels + ch] ;
145
146
/* Save current ratio rather then target ratio. */
147
state->last_ratio = src_ratio ;
148
149
data->input_frames_used = priv->in_used / state->channels ;
150
data->output_frames_gen = priv->out_gen / state->channels ;
151
152
return SRC_ERR_NO_ERROR ;
153
} /* linear_vari_process */
154
155
/*------------------------------------------------------------------------------
156
*/
157
158
#if 0
159
LIBSAMPLERATE_DLL_PRIVATE const char*
160
linear_get_name (int src_enum)
161
{
162
if (src_enum == SRC_LINEAR)
163
return "Linear Interpolator" ;
164
165
return NULL ;
166
} /* linear_get_name */
167
168
LIBSAMPLERATE_DLL_PRIVATE const char*
169
linear_get_description (int src_enum)
170
{
171
if (src_enum == SRC_LINEAR)
172
return "Linear interpolator, very fast, poor quality." ;
173
174
return NULL ;
175
} /* linear_get_descrition */
176
#endif
177
178
static LINEAR_DATA *
179
linear_data_new (int channels)
180
{
181
assert (channels > 0) ;
182
183
LINEAR_DATA *priv = (LINEAR_DATA *) calloc (1, sizeof (LINEAR_DATA)) ;
184
if (priv)
185
{
186
priv->linear_magic_marker = LINEAR_MAGIC_MARKER ;
187
priv->last_value = (float *) calloc (channels, sizeof (float)) ;
188
if (!priv->last_value)
189
{
190
free (priv) ;
191
priv = NULL ;
192
}
193
}
194
195
return priv ;
196
}
197
198
LIBSAMPLERATE_DLL_PRIVATE SRC_STATE *
199
linear_state_new (int channels, SRC_ERROR *error)
200
{
201
assert (channels > 0) ;
202
assert (error != NULL) ;
203
204
SRC_STATE *state = (SRC_STATE *) calloc (1, sizeof (SRC_STATE)) ;
205
if (!state)
206
{
207
*error = SRC_ERR_MALLOC_FAILED ;
208
return NULL ;
209
}
210
211
state->channels = channels ;
212
state->mode = SRC_MODE_PROCESS ;
213
214
state->private_data = linear_data_new (state->channels) ;
215
if (!state->private_data)
216
{
217
free (state) ;
218
*error = SRC_ERR_MALLOC_FAILED ;
219
return NULL ;
220
}
221
222
state->vt = &linear_state_vt ;
223
224
linear_reset (state) ;
225
226
*error = SRC_ERR_NO_ERROR ;
227
228
return state ;
229
}
230
231
/*===================================================================================
232
*/
233
234
static void
235
linear_reset (SRC_STATE *state)
236
{ LINEAR_DATA *priv = NULL ;
237
238
priv = (LINEAR_DATA*) state->private_data ;
239
if (priv == NULL)
240
return ;
241
242
priv->dirty = false ;
243
memset (priv->last_value, 0, sizeof (priv->last_value [0]) * state->channels) ;
244
245
return ;
246
} /* linear_reset */
247
248
SRC_STATE *
249
linear_copy (SRC_STATE *state)
250
{
251
assert (state != NULL) ;
252
253
if (state->private_data == NULL)
254
return NULL ;
255
256
SRC_STATE *to = (SRC_STATE *) calloc (1, sizeof (SRC_STATE)) ;
257
if (!to)
258
return NULL ;
259
memcpy (to, state, sizeof (SRC_STATE)) ;
260
261
LINEAR_DATA* from_priv = (LINEAR_DATA*) state->private_data ;
262
LINEAR_DATA *to_priv = (LINEAR_DATA *) calloc (1, sizeof (LINEAR_DATA)) ;
263
if (!to_priv)
264
{
265
free (to) ;
266
return NULL ;
267
}
268
269
memcpy (to_priv, from_priv, sizeof (LINEAR_DATA)) ;
270
to_priv->last_value = (float *) malloc (sizeof (float) * state->channels) ;
271
if (!to_priv->last_value)
272
{
273
free (to) ;
274
free (to_priv) ;
275
return NULL ;
276
}
277
memcpy (to_priv->last_value, from_priv->last_value, sizeof (float) * state->channels) ;
278
279
to->private_data = to_priv ;
280
281
return to ;
282
} /* linear_copy */
283
284
static void
285
linear_close (SRC_STATE *state)
286
{
287
if (state)
288
{
289
LINEAR_DATA *linear = (LINEAR_DATA *) state->private_data ;
290
if (linear)
291
{
292
if (linear->last_value)
293
{
294
free (linear->last_value) ;
295
linear->last_value = NULL ;
296
}
297
free (linear) ;
298
linear = NULL ;
299
}
300
free (state) ;
301
state = NULL ;
302
}
303
} /* linear_close */
304
305