2 ** Copyright (C) 2002-2008 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 Rabibt 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 linear_vari_process (SRC_PRIVATE
*psrc
, SRC_DATA
*data
) ;
34 static void linear_reset (SRC_PRIVATE
*psrc
) ;
36 /*========================================================================================
39 #define LINEAR_MAGIC_MARKER MAKE_MAGIC ('l', 'i', 'n', 'e', 'a', 'r')
44 { int linear_magic_marker
;
47 long in_count
, in_used
;
48 long out_count
, out_gen
;
49 float last_value
[1] ;
52 /*----------------------------------------------------------------------------------------
56 linear_vari_process (SRC_PRIVATE
*psrc
, SRC_DATA
*data
)
58 double src_ratio
, input_index
, rem
;
61 if (psrc
->private_data
== NULL
)
62 return SRC_ERR_NO_PRIVATE
;
64 priv
= (LINEAR_DATA
*) psrc
->private_data
;
67 { /* If we have just been reset, set the last_value data. */
68 for (ch
= 0 ; ch
< priv
->channels
; ch
++)
69 priv
->last_value
[ch
] = data
->data_in
[ch
] ;
73 priv
->in_count
= data
->input_frames
* priv
->channels
;
74 priv
->out_count
= data
->output_frames
* priv
->channels
;
75 priv
->in_used
= priv
->out_gen
= 0 ;
77 src_ratio
= psrc
->last_ratio
;
78 input_index
= psrc
->last_position
;
80 /* Calculate samples before first sample in input array. */
81 while (input_index
< 1.0 && priv
->out_gen
< priv
->out_count
)
83 if (priv
->in_used
+ priv
->channels
* (1.0 + input_index
) >= priv
->in_count
)
86 if (priv
->out_count
> 0 && fabs (psrc
->last_ratio
- data
->src_ratio
) > SRC_MIN_RATIO_DIFF
)
87 src_ratio
= psrc
->last_ratio
+ priv
->out_gen
* (data
->src_ratio
- psrc
->last_ratio
) / priv
->out_count
;
89 for (ch
= 0 ; ch
< priv
->channels
; ch
++)
90 { data
->data_out
[priv
->out_gen
] = (float) (priv
->last_value
[ch
] + input_index
*
91 (data
->data_in
[ch
] - 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 if (SRC_DEBUG
&& priv
->in_used
< priv
->channels
&& input_index
< 1.0)
110 { printf ("Whoops!!!! in_used : %ld channels : %d input_index : %f\n", priv
->in_used
, priv
->channels
, input_index
) ;
114 for (ch
= 0 ; ch
< priv
->channels
; ch
++)
115 { data
->data_out
[priv
->out_gen
] = (float) (data
->data_in
[priv
->in_used
- priv
->channels
+ ch
] + input_index
*
116 (data
->data_in
[priv
->in_used
+ ch
] - data
->data_in
[priv
->in_used
- priv
->channels
+ ch
])) ;
120 /* Figure out the next index. */
121 input_index
+= 1.0 / src_ratio
;
122 rem
= fmod_one (input_index
) ;
124 priv
->in_used
+= priv
->channels
* lrint (input_index
- rem
) ;
128 if (priv
->in_used
> priv
->in_count
)
129 { input_index
+= (priv
->in_used
- priv
->in_count
) / priv
->channels
;
130 priv
->in_used
= priv
->in_count
;
133 psrc
->last_position
= input_index
;
135 if (priv
->in_used
> 0)
136 for (ch
= 0 ; ch
< priv
->channels
; ch
++)
137 priv
->last_value
[ch
] = data
->data_in
[priv
->in_used
- priv
->channels
+ ch
] ;
139 /* Save current ratio rather then target ratio. */
140 psrc
->last_ratio
= src_ratio
;
142 data
->input_frames_used
= priv
->in_used
/ priv
->channels
;
143 data
->output_frames_gen
= priv
->out_gen
/ priv
->channels
;
145 return SRC_ERR_NO_ERROR
;
146 } /* linear_vari_process */
148 /*------------------------------------------------------------------------------
152 linear_get_name (int src_enum
)
154 if (src_enum
== SRC_LINEAR
)
155 return "Linear Interpolator" ;
158 } /* linear_get_name */
161 linear_get_description (int src_enum
)
163 if (src_enum
== SRC_LINEAR
)
164 return "Linear interpolator, very fast, poor quality." ;
167 } /* linear_get_descrition */
170 linear_set_converter (SRC_PRIVATE
*psrc
, int src_enum
)
171 { LINEAR_DATA
*priv
= NULL
;
173 if (src_enum
!= SRC_LINEAR
)
174 return SRC_ERR_BAD_CONVERTER
;
176 if (psrc
->private_data
!= NULL
)
177 { free (psrc
->private_data
) ;
178 psrc
->private_data
= NULL
;
181 if (psrc
->private_data
== NULL
)
182 { priv
= calloc (1, sizeof (*priv
) + psrc
->channels
* sizeof (float)) ;
184 return SRC_ERR_MALLOC_FAILED
;
185 psrc
->private_data
= priv
;
188 priv
->linear_magic_marker
= LINEAR_MAGIC_MARKER
;
189 priv
->channels
= psrc
->channels
;
191 psrc
->const_process
= linear_vari_process
;
192 psrc
->vari_process
= linear_vari_process
;
193 psrc
->reset
= linear_reset
;
195 linear_reset (psrc
) ;
197 return SRC_ERR_NO_ERROR
;
198 } /* linear_set_converter */
200 /*===================================================================================
204 linear_reset (SRC_PRIVATE
*psrc
)
205 { LINEAR_DATA
*priv
= NULL
;
207 priv
= (LINEAR_DATA
*) psrc
->private_data
;
211 priv
->channels
= psrc
->channels
;
213 memset (priv
->last_value
, 0, sizeof (priv
->last_value
[0]) * priv
->channels
) ;