]> git.sesse.net Git - vlc/blob - modules/audio_filter/resampler/linear.c
5d61ca479eceffb4d1dd016cf1f4793802f91047
[vlc] / modules / audio_filter / resampler / linear.c
1 /*****************************************************************************
2  * linear.c : linear interpolation resampler
3  *****************************************************************************
4  * Copyright (C) 2002 VideoLAN
5  * $Id: linear.c,v 1.5 2002/11/15 00:41:00 gbazin Exp $
6  *
7  * Authors: Gildas Bazin <gbazin@netcourrier.com>
8  *          Sigmund Augdal <sigmunau@idi.ntnu.no>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  * 
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <errno.h>
29 #include <stdlib.h>                                      /* malloc(), free() */
30 #include <string.h>
31
32 #include <vlc/vlc.h>
33 #include "audio_output.h"
34 #include "aout_internal.h"
35
36 /*****************************************************************************
37  * Local prototypes
38  *****************************************************************************/
39 static int  Create    ( vlc_object_t * );
40 static void Close     ( vlc_object_t * );
41 static void DoWork    ( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
42                         aout_buffer_t * );
43
44 /*****************************************************************************
45  * Local structures
46  *****************************************************************************/
47 struct aout_filter_sys_t
48 {
49     int32_t *p_prev_sample;       /* this filter introduces a 1 sample delay */
50
51     int     i_remainder;                     /* remainder of previous sample */
52
53     audio_date_t end_date;
54 };
55
56 /*****************************************************************************
57  * Module descriptor
58  *****************************************************************************/
59 vlc_module_begin();
60     set_description( _("audio filter for linear interpolation resampling") );
61     set_capability( "audio filter", 10 );
62     set_callbacks( Create, Close );
63 vlc_module_end();
64
65 /*****************************************************************************
66  * Create: allocate linear resampler
67  *****************************************************************************/
68 static int Create( vlc_object_t *p_this )
69 {
70     aout_filter_t * p_filter = (aout_filter_t *)p_this;
71     if ( p_filter->input.i_rate == p_filter->output.i_rate
72           || p_filter->input.i_format != p_filter->output.i_format
73           || p_filter->input.i_physical_channels
74               != p_filter->output.i_physical_channels
75           || p_filter->input.i_original_channels
76               != p_filter->output.i_original_channels
77           || p_filter->input.i_format != VLC_FOURCC('f','l','3','2') )
78     {
79         return VLC_EGENERIC;
80     }
81
82     /* Allocate the memory needed to store the module's structure */
83     p_filter->p_sys = malloc( sizeof(struct aout_filter_sys_t) );
84     if( p_filter->p_sys == NULL )
85     {
86         msg_Err( p_filter, "out of memory" );
87         return VLC_ENOMEM;
88     }
89     p_filter->p_sys->p_prev_sample = malloc(
90         p_filter->input.i_physical_channels * sizeof(int32_t) );
91     if( p_filter->p_sys->p_prev_sample == NULL )
92     {
93         msg_Err( p_filter, "out of memory" );
94         return VLC_ENOMEM;
95     }
96
97     p_filter->pf_do_work = DoWork;
98     p_filter->b_in_place = VLC_FALSE;
99
100     return VLC_SUCCESS;
101 }
102
103 /*****************************************************************************
104  * Close: free our resources
105  *****************************************************************************/
106 static void Close( vlc_object_t * p_this )
107 {
108     aout_filter_t * p_filter = (aout_filter_t *)p_this;
109     free( p_filter->p_sys->p_prev_sample );
110     free( p_filter->p_sys );
111 }
112
113 /*****************************************************************************
114  * DoWork: convert a buffer
115  *****************************************************************************/
116 static void DoWork( aout_instance_t * p_aout, aout_filter_t * p_filter,
117                     aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
118 {
119     float* p_in = (float*)p_in_buf->p_buffer;
120     float* p_out = (float*)p_out_buf->p_buffer;
121     float* p_prev_sample = (float*)p_filter->p_sys->p_prev_sample;
122
123     int i_nb_channels = aout_FormatNbChannels( &p_filter->input );
124     int i_in_nb = p_in_buf->i_nb_samples;
125     int i_chan, i_in, i_out = 0;
126
127     /* Take care of the previous input sample (if any) */
128     if( p_filter->b_reinit )
129     {
130         p_filter->b_reinit = VLC_FALSE;
131         p_filter->p_sys->i_remainder = 0;
132         aout_DateInit( &p_filter->p_sys->end_date, p_filter->output.i_rate );
133     }
134     else
135     {
136         while( p_filter->p_sys->i_remainder < p_filter->output.i_rate )
137         {
138             for( i_chan = i_nb_channels ; i_chan ; )
139             {
140                 i_chan--;
141                 p_out[i_chan] = p_prev_sample[i_chan];
142                 p_out[i_chan] += ( (p_prev_sample[i_chan] - p_in[i_chan])
143                                    * p_filter->p_sys->i_remainder
144                                    / p_filter->output.i_rate );
145             }
146             p_out += i_nb_channels;
147             i_out++;
148
149             p_filter->p_sys->i_remainder += p_filter->input.i_rate;
150         }
151         p_filter->p_sys->i_remainder -= p_filter->output.i_rate;
152     }
153
154     /* Take care of the current input samples (minus last one) */
155     for( i_in = 0; i_in < i_in_nb - 1; i_in++ )
156     {
157         while( p_filter->p_sys->i_remainder < p_filter->output.i_rate )
158         {
159             for( i_chan = i_nb_channels ; i_chan ; )
160             {
161                 i_chan--;
162                 p_out[i_chan] = p_in[i_chan];
163                 p_out[i_chan] += ( (p_in[i_chan] -
164                     p_in[i_chan + i_nb_channels])
165                     * p_filter->p_sys->i_remainder / p_filter->output.i_rate );
166             }
167             p_out += i_nb_channels;
168             i_out++;
169
170             p_filter->p_sys->i_remainder += p_filter->input.i_rate;
171         }
172
173         p_in += i_nb_channels;
174         p_filter->p_sys->i_remainder -= p_filter->output.i_rate;
175     }
176
177     /* Backup the last input sample for next time */
178     for( i_chan = i_nb_channels ; i_chan ; )
179     {
180         i_chan--;
181         p_prev_sample[i_chan] = p_in[i_chan];
182     }
183
184     p_out_buf->i_nb_samples = i_out;
185     p_out_buf->start_date = p_in_buf->start_date;
186
187     if( p_in_buf->start_date !=
188         aout_DateGet( &p_filter->p_sys->end_date ) )
189     {
190         aout_DateSet( &p_filter->p_sys->end_date, p_in_buf->start_date );
191     }
192
193     p_out_buf->end_date = aout_DateIncrement( &p_filter->p_sys->end_date,
194                                               p_out_buf->i_nb_samples );
195
196     p_out_buf->i_nb_bytes = p_out_buf->i_nb_samples *
197         i_nb_channels * sizeof(int32_t);
198
199 }