2 ** Copyright (c) 2002-2016, Erik de Castro Lopo <erikd@mega-nerd.com>
3 ** All rights reserved.
5 ** This code is released under 2-clause BSD license. Please see the
6 ** file at : https://github.com/erikd/libsamplerate/blob/master/COPYING
11 static int zoh_vari_process (SRC_PRIVATE
*psrc
, SRC_DATA
*data
) ;
12 static void zoh_reset (SRC_PRIVATE
*psrc
) ;
14 /*========================================================================================
17 #define ZOH_MAGIC_MARKER MAKE_MAGIC ('s', 'r', 'c', 'z', 'o', 'h')
20 { int zoh_magic_marker
;
23 long in_count
, in_used
;
24 long out_count
, out_gen
;
25 float last_value
[1] ;
28 /*----------------------------------------------------------------------------------------
32 zoh_vari_process (SRC_PRIVATE
*psrc
, SRC_DATA
*data
)
34 double src_ratio
, input_index
, rem
;
37 if (data
->input_frames
<= 0)
38 return SRC_ERR_NO_ERROR
;
40 if (psrc
->private_data
== NULL
)
41 return SRC_ERR_NO_PRIVATE
;
43 priv
= (ZOH_DATA
*) psrc
->private_data
;
46 { /* If we have just been reset, set the last_value data. */
47 for (ch
= 0 ; ch
< priv
->channels
; ch
++)
48 priv
->last_value
[ch
] = data
->data_in
[ch
] ;
52 priv
->in_count
= data
->input_frames
* priv
->channels
;
53 priv
->out_count
= data
->output_frames
* priv
->channels
;
54 priv
->in_used
= priv
->out_gen
= 0 ;
56 src_ratio
= psrc
->last_ratio
;
58 if (is_bad_src_ratio (src_ratio
))
59 return SRC_ERR_BAD_INTERNAL_STATE
;
61 input_index
= psrc
->last_position
;
63 /* Calculate samples before first sample in input array. */
64 while (input_index
< 1.0 && priv
->out_gen
< priv
->out_count
)
66 if (priv
->in_used
+ priv
->channels
* input_index
>= priv
->in_count
)
69 if (priv
->out_count
> 0 && fabs (psrc
->last_ratio
- data
->src_ratio
) > SRC_MIN_RATIO_DIFF
)
70 src_ratio
= psrc
->last_ratio
+ priv
->out_gen
* (data
->src_ratio
- psrc
->last_ratio
) / priv
->out_count
;
72 for (ch
= 0 ; ch
< priv
->channels
; ch
++)
73 { data
->data_out
[priv
->out_gen
] = priv
->last_value
[ch
] ;
77 /* Figure out the next index. */
78 input_index
+= 1.0 / src_ratio
;
81 rem
= fmod_one (input_index
) ;
82 priv
->in_used
+= priv
->channels
* lrint (input_index
- rem
) ;
85 /* Main processing loop. */
86 while (priv
->out_gen
< priv
->out_count
&& priv
->in_used
+ priv
->channels
* input_index
<= priv
->in_count
)
88 if (priv
->out_count
> 0 && fabs (psrc
->last_ratio
- data
->src_ratio
) > SRC_MIN_RATIO_DIFF
)
89 src_ratio
= psrc
->last_ratio
+ priv
->out_gen
* (data
->src_ratio
- psrc
->last_ratio
) / priv
->out_count
;
91 for (ch
= 0 ; ch
< priv
->channels
; ch
++)
92 { data
->data_out
[priv
->out_gen
] = data
->data_in
[priv
->in_used
- priv
->channels
+ ch
] ;
96 /* Figure out the next index. */
97 input_index
+= 1.0 / src_ratio
;
98 rem
= fmod_one (input_index
) ;
100 priv
->in_used
+= priv
->channels
* lrint (input_index
- rem
) ;
104 if (priv
->in_used
> priv
->in_count
)
105 { input_index
+= (priv
->in_used
- priv
->in_count
) / priv
->channels
;
106 priv
->in_used
= priv
->in_count
;
109 psrc
->last_position
= input_index
;
111 if (priv
->in_used
> 0)
112 for (ch
= 0 ; ch
< priv
->channels
; ch
++)
113 priv
->last_value
[ch
] = data
->data_in
[priv
->in_used
- priv
->channels
+ ch
] ;
115 /* Save current ratio rather then target ratio. */
116 psrc
->last_ratio
= src_ratio
;
118 data
->input_frames_used
= priv
->in_used
/ priv
->channels
;
119 data
->output_frames_gen
= priv
->out_gen
/ priv
->channels
;
121 return SRC_ERR_NO_ERROR
;
122 } /* zoh_vari_process */
124 /*------------------------------------------------------------------------------
128 zoh_get_name (int src_enum
)
130 if (src_enum
== SRC_ZERO_ORDER_HOLD
)
131 return "ZOH Interpolator" ;
137 zoh_get_description (int src_enum
)
139 if (src_enum
== SRC_ZERO_ORDER_HOLD
)
140 return "Zero order hold interpolator, very fast, poor quality." ;
143 } /* zoh_get_descrition */
146 zoh_set_converter (SRC_PRIVATE
*psrc
, int src_enum
)
147 { ZOH_DATA
*priv
= NULL
;
149 if (src_enum
!= SRC_ZERO_ORDER_HOLD
)
150 return SRC_ERR_BAD_CONVERTER
;
152 if (psrc
->private_data
!= NULL
)
153 { free (psrc
->private_data
) ;
154 psrc
->private_data
= NULL
;
157 if (psrc
->private_data
== NULL
)
158 { priv
= calloc (1, sizeof (*priv
) + psrc
->channels
* sizeof (float)) ;
159 psrc
->private_data
= priv
;
163 return SRC_ERR_MALLOC_FAILED
;
165 priv
->zoh_magic_marker
= ZOH_MAGIC_MARKER
;
166 priv
->channels
= psrc
->channels
;
168 psrc
->const_process
= zoh_vari_process
;
169 psrc
->vari_process
= zoh_vari_process
;
170 psrc
->reset
= zoh_reset
;
174 return SRC_ERR_NO_ERROR
;
175 } /* zoh_set_converter */
177 /*===================================================================================
181 zoh_reset (SRC_PRIVATE
*psrc
)
184 priv
= (ZOH_DATA
*) psrc
->private_data
;
188 priv
->channels
= psrc
->channels
;
190 memset (priv
->last_value
, 0, sizeof (priv
->last_value
[0]) * priv
->channels
) ;