Bundle libsamplerate
[audio-libsamplerate.git] / libsamplerate / src / src_zoh.c
CommitLineData
8529da43
MG
1/*
2** Copyright (c) 2002-2016, 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/erikd/libsamplerate/blob/master/COPYING
7*/
8
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12
13#include "config.h"
14#include "float_cast.h"
15#include "common.h"
16
17static int zoh_vari_process (SRC_PRIVATE *psrc, SRC_DATA *data) ;
18static void zoh_reset (SRC_PRIVATE *psrc) ;
19
20/*========================================================================================
21*/
22
23#define ZOH_MAGIC_MARKER MAKE_MAGIC ('s', 'r', 'c', 'z', 'o', 'h')
24
25typedef struct
26{ int zoh_magic_marker ;
27 int channels ;
28 int reset ;
29 long in_count, in_used ;
30 long out_count, out_gen ;
31 float last_value [1] ;
32} ZOH_DATA ;
33
34/*----------------------------------------------------------------------------------------
35*/
36
37static int
38zoh_vari_process (SRC_PRIVATE *psrc, SRC_DATA *data)
39{ ZOH_DATA *priv ;
40 double src_ratio, input_index, rem ;
41 int ch ;
42
43 if (data->input_frames <= 0)
44 return SRC_ERR_NO_ERROR ;
45
46 if (psrc->private_data == NULL)
47 return SRC_ERR_NO_PRIVATE ;
48
49 priv = (ZOH_DATA*) psrc->private_data ;
50
51 if (priv->reset)
52 { /* If we have just been reset, set the last_value data. */
53 for (ch = 0 ; ch < priv->channels ; ch++)
54 priv->last_value [ch] = data->data_in [ch] ;
55 priv->reset = 0 ;
56 } ;
57
58 priv->in_count = data->input_frames * priv->channels ;
59 priv->out_count = data->output_frames * priv->channels ;
60 priv->in_used = priv->out_gen = 0 ;
61
62 src_ratio = psrc->last_ratio ;
63
64 if (is_bad_src_ratio (src_ratio))
65 return SRC_ERR_BAD_INTERNAL_STATE ;
66
67 input_index = psrc->last_position ;
68
69 /* Calculate samples before first sample in input array. */
70 while (input_index < 1.0 && priv->out_gen < priv->out_count)
71 {
72 if (priv->in_used + priv->channels * input_index >= priv->in_count)
73 break ;
74
75 if (priv->out_count > 0 && fabs (psrc->last_ratio - data->src_ratio) > SRC_MIN_RATIO_DIFF)
76 src_ratio = psrc->last_ratio + priv->out_gen * (data->src_ratio - psrc->last_ratio) / priv->out_count ;
77
78 for (ch = 0 ; ch < priv->channels ; ch++)
79 { data->data_out [priv->out_gen] = priv->last_value [ch] ;
80 priv->out_gen ++ ;
81 } ;
82
83 /* Figure out the next index. */
84 input_index += 1.0 / src_ratio ;
85 } ;
86
87 rem = fmod_one (input_index) ;
88 priv->in_used += priv->channels * lrint (input_index - rem) ;
89 input_index = rem ;
90
91 /* Main processing loop. */
92 while (priv->out_gen < priv->out_count && priv->in_used + priv->channels * input_index <= priv->in_count)
93 {
94 if (priv->out_count > 0 && fabs (psrc->last_ratio - data->src_ratio) > SRC_MIN_RATIO_DIFF)
95 src_ratio = psrc->last_ratio + priv->out_gen * (data->src_ratio - psrc->last_ratio) / priv->out_count ;
96
97 for (ch = 0 ; ch < priv->channels ; ch++)
98 { data->data_out [priv->out_gen] = data->data_in [priv->in_used - priv->channels + ch] ;
99 priv->out_gen ++ ;
100 } ;
101
102 /* Figure out the next index. */
103 input_index += 1.0 / src_ratio ;
104 rem = fmod_one (input_index) ;
105
106 priv->in_used += priv->channels * lrint (input_index - rem) ;
107 input_index = rem ;
108 } ;
109
110 if (priv->in_used > priv->in_count)
111 { input_index += (priv->in_used - priv->in_count) / priv->channels ;
112 priv->in_used = priv->in_count ;
113 } ;
114
115 psrc->last_position = input_index ;
116
117 if (priv->in_used > 0)
118 for (ch = 0 ; ch < priv->channels ; ch++)
119 priv->last_value [ch] = data->data_in [priv->in_used - priv->channels + ch] ;
120
121 /* Save current ratio rather then target ratio. */
122 psrc->last_ratio = src_ratio ;
123
124 data->input_frames_used = priv->in_used / priv->channels ;
125 data->output_frames_gen = priv->out_gen / priv->channels ;
126
127 return SRC_ERR_NO_ERROR ;
128} /* zoh_vari_process */
129
130/*------------------------------------------------------------------------------
131*/
132
133const char*
134zoh_get_name (int src_enum)
135{
136 if (src_enum == SRC_ZERO_ORDER_HOLD)
137 return "ZOH Interpolator" ;
138
139 return NULL ;
140} /* zoh_get_name */
141
142const char*
143zoh_get_description (int src_enum)
144{
145 if (src_enum == SRC_ZERO_ORDER_HOLD)
146 return "Zero order hold interpolator, very fast, poor quality." ;
147
148 return NULL ;
149} /* zoh_get_descrition */
150
151int
152zoh_set_converter (SRC_PRIVATE *psrc, int src_enum)
153{ ZOH_DATA *priv = NULL ;
154
155 if (src_enum != SRC_ZERO_ORDER_HOLD)
156 return SRC_ERR_BAD_CONVERTER ;
157
158 if (psrc->private_data != NULL)
159 { free (psrc->private_data) ;
160 psrc->private_data = NULL ;
161 } ;
162
163 if (psrc->private_data == NULL)
164 { priv = calloc (1, sizeof (*priv) + psrc->channels * sizeof (float)) ;
165 psrc->private_data = priv ;
166 } ;
167
168 if (priv == NULL)
169 return SRC_ERR_MALLOC_FAILED ;
170
171 priv->zoh_magic_marker = ZOH_MAGIC_MARKER ;
172 priv->channels = psrc->channels ;
173
174 psrc->const_process = zoh_vari_process ;
175 psrc->vari_process = zoh_vari_process ;
176 psrc->reset = zoh_reset ;
177
178 zoh_reset (psrc) ;
179
180 return SRC_ERR_NO_ERROR ;
181} /* zoh_set_converter */
182
183/*===================================================================================
184*/
185
186static void
187zoh_reset (SRC_PRIVATE *psrc)
188{ ZOH_DATA *priv ;
189
190 priv = (ZOH_DATA*) psrc->private_data ;
191 if (priv == NULL)
192 return ;
193
194 priv->channels = psrc->channels ;
195 priv->reset = 1 ;
196 memset (priv->last_value, 0, sizeof (priv->last_value [0]) * priv->channels) ;
197
198 return ;
199} /* zoh_reset */
200
This page took 0.019467 seconds and 4 git commands to generate.