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
14 #include "float_cast.h"
17 static int zoh_vari_process (SRC_PRIVATE
*psrc
, SRC_DATA
*data
) ;
18 static void zoh_reset (SRC_PRIVATE
*psrc
) ;
20 /*========================================================================================
23 #define ZOH_MAGIC_MARKER MAKE_MAGIC ('s', 'r', 'c', 'z', 'o', 'h')
26 { int zoh_magic_marker
;
29 long in_count
, in_used
;
30 long out_count
, out_gen
;
31 float last_value
[1] ;
34 /*----------------------------------------------------------------------------------------
38 zoh_vari_process (SRC_PRIVATE
*psrc
, SRC_DATA
*data
)
40 double src_ratio
, input_index
, rem
;
43 if (data
->input_frames
<= 0)
44 return SRC_ERR_NO_ERROR
;
46 if (psrc
->private_data
== NULL
)
47 return SRC_ERR_NO_PRIVATE
;
49 priv
= (ZOH_DATA
*) psrc
->private_data
;
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
] ;
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 ;
62 src_ratio
= psrc
->last_ratio
;
64 if (is_bad_src_ratio (src_ratio
))
65 return SRC_ERR_BAD_INTERNAL_STATE
;
67 input_index
= psrc
->last_position
;
69 /* Calculate samples before first sample in input array. */
70 while (input_index
< 1.0 && priv
->out_gen
< priv
->out_count
)
72 if (priv
->in_used
+ priv
->channels
* input_index
>= priv
->in_count
)
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
;
78 for (ch
= 0 ; ch
< priv
->channels
; ch
++)
79 { data
->data_out
[priv
->out_gen
] = priv
->last_value
[ch
] ;
83 /* Figure out the next index. */
84 input_index
+= 1.0 / src_ratio
;
87 rem
= fmod_one (input_index
) ;
88 priv
->in_used
+= priv
->channels
* lrint (input_index
- rem
) ;
91 /* Main processing loop. */
92 while (priv
->out_gen
< priv
->out_count
&& priv
->in_used
+ priv
->channels
* input_index
<= priv
->in_count
)
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
;
97 for (ch
= 0 ; ch
< priv
->channels
; ch
++)
98 { data
->data_out
[priv
->out_gen
] = data
->data_in
[priv
->in_used
- priv
->channels
+ ch
] ;
102 /* Figure out the next index. */
103 input_index
+= 1.0 / src_ratio
;
104 rem
= fmod_one (input_index
) ;
106 priv
->in_used
+= priv
->channels
* lrint (input_index
- rem
) ;
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
;
115 psrc
->last_position
= input_index
;
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
] ;
121 /* Save current ratio rather then target ratio. */
122 psrc
->last_ratio
= src_ratio
;
124 data
->input_frames_used
= priv
->in_used
/ priv
->channels
;
125 data
->output_frames_gen
= priv
->out_gen
/ priv
->channels
;
127 return SRC_ERR_NO_ERROR
;
128 } /* zoh_vari_process */
130 /*------------------------------------------------------------------------------
134 zoh_get_name (int src_enum
)
136 if (src_enum
== SRC_ZERO_ORDER_HOLD
)
137 return "ZOH Interpolator" ;
143 zoh_get_description (int src_enum
)
145 if (src_enum
== SRC_ZERO_ORDER_HOLD
)
146 return "Zero order hold interpolator, very fast, poor quality." ;
149 } /* zoh_get_descrition */
152 zoh_set_converter (SRC_PRIVATE
*psrc
, int src_enum
)
153 { ZOH_DATA
*priv
= NULL
;
155 if (src_enum
!= SRC_ZERO_ORDER_HOLD
)
156 return SRC_ERR_BAD_CONVERTER
;
158 if (psrc
->private_data
!= NULL
)
159 { free (psrc
->private_data
) ;
160 psrc
->private_data
= NULL
;
163 if (psrc
->private_data
== NULL
)
164 { priv
= calloc (1, sizeof (*priv
) + psrc
->channels
* sizeof (float)) ;
165 psrc
->private_data
= priv
;
169 return SRC_ERR_MALLOC_FAILED
;
171 priv
->zoh_magic_marker
= ZOH_MAGIC_MARKER
;
172 priv
->channels
= psrc
->channels
;
174 psrc
->const_process
= zoh_vari_process
;
175 psrc
->vari_process
= zoh_vari_process
;
176 psrc
->reset
= zoh_reset
;
180 return SRC_ERR_NO_ERROR
;
181 } /* zoh_set_converter */
183 /*===================================================================================
187 zoh_reset (SRC_PRIVATE
*psrc
)
190 priv
= (ZOH_DATA
*) psrc
->private_data
;
194 priv
->channels
= psrc
->channels
;
196 memset (priv
->last_value
, 0, sizeof (priv
->last_value
[0]) * priv
->channels
) ;