2 ** Copyright (C) 2002-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
4 ** This program is free software; you can redistribute it and/or modify
5 ** it under the terms of the GNU General Public License as published by
6 ** the Free Software Foundation; either version 2 of the License, or
7 ** (at your option) any later version.
9 ** This program is distributed in the hope that it will be useful,
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 ** GNU General Public License for more details.
14 ** You should have received a copy of the GNU General Public License
15 ** along with this program; if not, write to the Free Software
16 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
20 ** This code is part of Secret Rabbit Code aka libsamplerate. A commercial
21 ** use license for this code is available, please see:
22 ** http://www.mega-nerd.com/SRC/procedure.html
30 #include "float_cast.h"
33 static int zoh_vari_process (SRC_PRIVATE
*psrc
, SRC_DATA
*data
) ;
34 static void zoh_reset (SRC_PRIVATE
*psrc
) ;
36 /*========================================================================================
39 #define ZOH_MAGIC_MARKER MAKE_MAGIC ('s', 'r', 'c', 'z', 'o', 'h')
42 { int zoh_magic_marker
;
45 long in_count
, in_used
;
46 long out_count
, out_gen
;
47 float last_value
[1] ;
50 /*----------------------------------------------------------------------------------------
54 zoh_vari_process (SRC_PRIVATE
*psrc
, SRC_DATA
*data
)
56 double src_ratio
, input_index
, rem
;
59 if (data
->input_frames
<= 0)
60 return SRC_ERR_NO_ERROR
;
62 if (psrc
->private_data
== NULL
)
63 return SRC_ERR_NO_PRIVATE
;
65 priv
= (ZOH_DATA
*) psrc
->private_data
;
68 { /* If we have just been reset, set the last_value data. */
69 for (ch
= 0 ; ch
< priv
->channels
; ch
++)
70 priv
->last_value
[ch
] = data
->data_in
[ch
] ;
74 priv
->in_count
= data
->input_frames
* priv
->channels
;
75 priv
->out_count
= data
->output_frames
* priv
->channels
;
76 priv
->in_used
= priv
->out_gen
= 0 ;
78 src_ratio
= psrc
->last_ratio
;
79 input_index
= psrc
->last_position
;
81 /* Calculate samples before first sample in input array. */
82 while (input_index
< 1.0 && priv
->out_gen
< priv
->out_count
)
84 if (priv
->in_used
+ priv
->channels
* input_index
>= priv
->in_count
)
87 if (priv
->out_count
> 0 && fabs (psrc
->last_ratio
- data
->src_ratio
) > SRC_MIN_RATIO_DIFF
)
88 src_ratio
= psrc
->last_ratio
+ priv
->out_gen
* (data
->src_ratio
- psrc
->last_ratio
) / priv
->out_count
;
90 for (ch
= 0 ; ch
< priv
->channels
; ch
++)
91 { data
->data_out
[priv
->out_gen
] = priv
->last_value
[ch
] ;
95 /* Figure out the next index. */
96 input_index
+= 1.0 / src_ratio
;
99 rem
= fmod_one (input_index
) ;
100 priv
->in_used
+= priv
->channels
* lrint (input_index
- rem
) ;
103 /* Main processing loop. */
104 while (priv
->out_gen
< priv
->out_count
&& priv
->in_used
+ priv
->channels
* input_index
<= priv
->in_count
)
106 if (priv
->out_count
> 0 && fabs (psrc
->last_ratio
- data
->src_ratio
) > SRC_MIN_RATIO_DIFF
)
107 src_ratio
= psrc
->last_ratio
+ priv
->out_gen
* (data
->src_ratio
- psrc
->last_ratio
) / priv
->out_count
;
109 for (ch
= 0 ; ch
< priv
->channels
; ch
++)
110 { data
->data_out
[priv
->out_gen
] = data
->data_in
[priv
->in_used
- priv
->channels
+ ch
] ;
114 /* Figure out the next index. */
115 input_index
+= 1.0 / src_ratio
;
116 rem
= fmod_one (input_index
) ;
118 priv
->in_used
+= priv
->channels
* lrint (input_index
- rem
) ;
122 if (priv
->in_used
> priv
->in_count
)
123 { input_index
+= (priv
->in_used
- priv
->in_count
) / priv
->channels
;
124 priv
->in_used
= priv
->in_count
;
127 psrc
->last_position
= input_index
;
129 if (priv
->in_used
> 0)
130 for (ch
= 0 ; ch
< priv
->channels
; ch
++)
131 priv
->last_value
[ch
] = data
->data_in
[priv
->in_used
- priv
->channels
+ ch
] ;
133 /* Save current ratio rather then target ratio. */
134 psrc
->last_ratio
= src_ratio
;
136 data
->input_frames_used
= priv
->in_used
/ priv
->channels
;
137 data
->output_frames_gen
= priv
->out_gen
/ priv
->channels
;
139 return SRC_ERR_NO_ERROR
;
140 } /* zoh_vari_process */
142 /*------------------------------------------------------------------------------
146 zoh_get_name (int src_enum
)
148 if (src_enum
== SRC_ZERO_ORDER_HOLD
)
149 return "ZOH Interpolator" ;
155 zoh_get_description (int src_enum
)
157 if (src_enum
== SRC_ZERO_ORDER_HOLD
)
158 return "Zero order hold interpolator, very fast, poor quality." ;
161 } /* zoh_get_descrition */
164 zoh_set_converter (SRC_PRIVATE
*psrc
, int src_enum
)
165 { ZOH_DATA
*priv
= NULL
;
167 if (src_enum
!= SRC_ZERO_ORDER_HOLD
)
168 return SRC_ERR_BAD_CONVERTER
;
170 if (psrc
->private_data
!= NULL
)
171 { free (psrc
->private_data
) ;
172 psrc
->private_data
= NULL
;
175 if (psrc
->private_data
== NULL
)
176 { priv
= calloc (1, sizeof (*priv
) + psrc
->channels
* sizeof (float)) ;
178 return SRC_ERR_MALLOC_FAILED
;
179 psrc
->private_data
= priv
;
182 priv
->zoh_magic_marker
= ZOH_MAGIC_MARKER
;
183 priv
->channels
= psrc
->channels
;
185 psrc
->const_process
= zoh_vari_process
;
186 psrc
->vari_process
= zoh_vari_process
;
187 psrc
->reset
= zoh_reset
;
191 return SRC_ERR_NO_ERROR
;
192 } /* zoh_set_converter */
194 /*===================================================================================
198 zoh_reset (SRC_PRIVATE
*psrc
)
201 priv
= (ZOH_DATA
*) psrc
->private_data
;
205 priv
->channels
= psrc
->channels
;
207 memset (priv
->last_value
, 0, sizeof (priv
->last_value
[0]) * priv
->channels
) ;