]> git.sesse.net Git - vlc/blob - modules/audio_filter/channel_mixer/headphone.c
* all: - increased avcodec version needed to 4680 (latest release)
[vlc] / modules / audio_filter / channel_mixer / headphone.c
1 /*****************************************************************************
2  * headphone.c : headphone virtual spatialization channel mixer module
3  *               -> gives the feeling of a real room with a simple headphone
4  *****************************************************************************
5  * Copyright (C) 2002 VideoLAN
6  * $Id: headphone.c,v 1.5 2003/05/15 22:27:37 massiot Exp $
7  *
8  * Authors: Boris Dorès <babal@via.ecp.fr>
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 <stdlib.h>                                      /* malloc(), free() */
29 #include <string.h>
30 #include <math.h>                                        /* sqrt */
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 Destroy   ( vlc_object_t * );
41
42 static void DoWork    ( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
43                         aout_buffer_t * );
44
45 /*****************************************************************************
46  * Module descriptor
47  *****************************************************************************/
48 #define HEADPHONE_DIM_TEXT N_("Characteristic dimension")
49 #define HEADPHONE_DIM_LONGTEXT N_( \
50      "Headphone virtual spatialization effect parameter: "\
51      "distance between front left speaker and listener in meters.")
52
53 vlc_module_begin();
54     add_category_hint( N_("headphone"), NULL, VLC_FALSE );
55     add_integer( "headphone-dim", 5, NULL, HEADPHONE_DIM_TEXT,
56                  HEADPHONE_DIM_LONGTEXT, VLC_TRUE );
57     set_description( _("headphone channel mixer with virtual spatialization effect") );
58     set_capability( "audio filter", 0 );
59     set_callbacks( Create, Destroy );
60     add_shortcut( "headphone" );
61 vlc_module_end();
62
63
64 /*****************************************************************************
65  * Internal data structures
66  *****************************************************************************/
67 struct atomic_operation_t
68 {
69     int i_source_channel_offset;
70     int i_dest_channel_offset;
71     unsigned int i_delay;/* in sample unit */
72     double d_amplitude_factor;
73 };
74
75 struct aout_filter_sys_t
76 {
77     size_t i_overflow_buffer_size;/* in bytes */
78     byte_t * p_overflow_buffer;
79     unsigned int i_nb_atomic_operations;
80     struct atomic_operation_t * p_atomic_operations;
81 };
82
83 /*****************************************************************************
84  * Init: initialize internal data structures
85  * and computes the needed atomic operations
86  *****************************************************************************/
87 /* x and z represent the coordinates of the virtual speaker
88  *  relatively to the center of the listener's head, measured in meters :
89  *
90  *  left              right
91  *Z
92  *-
93  *a          head
94  *x
95  *i
96  *s
97  *  rear left    rear right
98  *
99  *          x-axis
100  *  */
101 static void ComputeChannelOperations ( struct aout_filter_sys_t * p_data
102         , unsigned int i_rate , unsigned int i_next_atomic_operation
103         , int i_source_channel_offset , double d_x , double d_z
104         , double d_channel_amplitude_factor )
105 {
106     double d_c = 340; /*sound celerity (unit: m/s)*/
107
108     /* Left ear */
109     p_data->p_atomic_operations[i_next_atomic_operation]
110         .i_source_channel_offset = i_source_channel_offset;
111     p_data->p_atomic_operations[i_next_atomic_operation]
112         .i_dest_channel_offset = 0;/* left */
113     p_data->p_atomic_operations[i_next_atomic_operation]
114         .i_delay = (int)( sqrt( (-0.1-d_x)*(-0.1-d_x) + (0-d_z)*(0-d_z) )
115                           / d_c * i_rate );
116     if ( d_x < 0 )
117     {
118         p_data->p_atomic_operations[i_next_atomic_operation]
119             .d_amplitude_factor = d_channel_amplitude_factor * 1.1 / 2;
120     }
121     else if ( d_x > 0 )
122     {
123         p_data->p_atomic_operations[i_next_atomic_operation]
124             .d_amplitude_factor = d_channel_amplitude_factor * 0.9 / 2;
125     }
126     else
127     {
128         p_data->p_atomic_operations[i_next_atomic_operation]
129             .d_amplitude_factor = d_channel_amplitude_factor / 2;
130     }
131
132     /* Right ear */
133     p_data->p_atomic_operations[i_next_atomic_operation + 1]
134         .i_source_channel_offset = i_source_channel_offset;
135     p_data->p_atomic_operations[i_next_atomic_operation + 1]
136         .i_dest_channel_offset = 1;/* right */
137     p_data->p_atomic_operations[i_next_atomic_operation + 1]
138         .i_delay = (int)( sqrt( (0.1-d_x)*(0.1-d_x) + (0-d_z)*(0-d_z) )
139                           / d_c * i_rate );
140     if ( d_x < 0 )
141     {
142         p_data->p_atomic_operations[i_next_atomic_operation + 1]
143             .d_amplitude_factor = d_channel_amplitude_factor * 0.9 / 2;
144     }
145     else if ( d_x > 0 )
146     {
147         p_data->p_atomic_operations[i_next_atomic_operation + 1]
148             .d_amplitude_factor = d_channel_amplitude_factor * 1.1 / 2;
149     }
150     else
151     {
152         p_data->p_atomic_operations[i_next_atomic_operation + 1]
153             .d_amplitude_factor = d_channel_amplitude_factor / 2;
154     }
155 }
156
157 static int Init ( aout_filter_t * p_filter , struct aout_filter_sys_t * p_data
158         , unsigned int i_nb_channels , uint32_t i_physical_channels
159         , unsigned int i_rate )
160 {
161     double d_x = config_GetInt ( p_filter , "headphone-dim" );
162     double d_z = d_x;
163     double d_z_rear = -d_x/3;
164     unsigned int i_next_atomic_operation;
165     int i_source_channel_offset;
166     unsigned int i;
167
168     if ( p_data == NULL )
169     {
170         msg_Dbg ( p_filter, "passing a null pointer as argument" );
171         return 0;
172     }
173
174     /* Number of elementary operations */
175     p_data->i_nb_atomic_operations = i_nb_channels * 2;
176     p_data->p_atomic_operations = malloc ( sizeof(struct atomic_operation_t)
177             * p_data->i_nb_atomic_operations );
178     if ( p_data->p_atomic_operations == NULL )
179     {
180         msg_Err( p_filter, "out of memory" );
181         return -1;
182     }
183
184     /* For each virtual speaker, computes elementary wave propagation time
185      * to each ear */
186     i_next_atomic_operation = 0;
187     i_source_channel_offset = 0;
188     if ( i_physical_channels & AOUT_CHAN_LEFT )
189     {
190         ComputeChannelOperations ( p_data , i_rate
191                 , i_next_atomic_operation , i_source_channel_offset
192                 , -d_x , d_z , 2.0 / i_nb_channels );
193         i_next_atomic_operation += 2;
194         i_source_channel_offset++;
195     }
196     if ( i_physical_channels & AOUT_CHAN_RIGHT )
197     {
198         ComputeChannelOperations ( p_data , i_rate
199                 , i_next_atomic_operation , i_source_channel_offset
200                 , d_x , d_z , 2.0 / i_nb_channels );
201         i_next_atomic_operation += 2;
202         i_source_channel_offset++;
203     }
204     if ( i_physical_channels & AOUT_CHAN_REARLEFT )
205     {
206         ComputeChannelOperations ( p_data , i_rate
207                 , i_next_atomic_operation , i_source_channel_offset
208                 , -d_x , d_z_rear , 1.5 / i_nb_channels );
209         i_next_atomic_operation += 2;
210         i_source_channel_offset++;
211     }
212     if ( i_physical_channels & AOUT_CHAN_REARRIGHT )
213     {
214         ComputeChannelOperations ( p_data , i_rate
215                 , i_next_atomic_operation , i_source_channel_offset
216                 , d_x , d_z_rear , 1.5 / i_nb_channels );
217         i_next_atomic_operation += 2;
218         i_source_channel_offset++;
219     }
220     if ( i_physical_channels & AOUT_CHAN_REARCENTER )
221     {
222         ComputeChannelOperations ( p_data , i_rate
223                 , i_next_atomic_operation , i_source_channel_offset
224                 , 0 , -d_z , 1.5 / i_nb_channels );
225         i_next_atomic_operation += 2;
226         i_source_channel_offset++;
227     }
228     if ( i_physical_channels & AOUT_CHAN_CENTER )
229     {
230         ComputeChannelOperations ( p_data , i_rate
231                 , i_next_atomic_operation , i_source_channel_offset
232                 , 0 , d_z , 1.5 / i_nb_channels );
233         i_next_atomic_operation += 2;
234         i_source_channel_offset++;
235     }
236     if ( i_physical_channels & AOUT_CHAN_LFE )
237     {
238         ComputeChannelOperations ( p_data , i_rate
239                 , i_next_atomic_operation , i_source_channel_offset
240                 , 0 , d_z_rear , 5.0 / i_nb_channels );
241         i_next_atomic_operation += 2;
242         i_source_channel_offset++;
243     }
244     if ( i_physical_channels & AOUT_CHAN_MIDDLELEFT )
245     {
246         ComputeChannelOperations ( p_data , i_rate
247                 , i_next_atomic_operation , i_source_channel_offset
248                 , -d_x , 0 , 1.5 / i_nb_channels );
249         i_next_atomic_operation += 2;
250         i_source_channel_offset++;
251     }
252     if ( i_physical_channels & AOUT_CHAN_MIDDLERIGHT )
253     {
254         ComputeChannelOperations ( p_data , i_rate
255                 , i_next_atomic_operation , i_source_channel_offset
256                 , d_x , 0 , 1.5 / i_nb_channels );
257         i_next_atomic_operation += 2;
258         i_source_channel_offset++;
259     }
260
261     /* Initialize the overflow buffer
262      * we need it because the process induce a delay in the samples */
263     p_data->i_overflow_buffer_size = 0;
264     for ( i = 0 ; i < p_data->i_nb_atomic_operations ; i++ )
265     {
266         if ( p_data->i_overflow_buffer_size
267                 < p_data->p_atomic_operations[i].i_delay * i_nb_channels
268                 * sizeof (float) )
269         {
270             p_data->i_overflow_buffer_size
271                 = p_data->p_atomic_operations[i].i_delay * i_nb_channels
272                 * sizeof (float);
273         }
274     }
275     p_data->p_overflow_buffer = malloc ( p_data->i_overflow_buffer_size );
276     if ( p_data->p_atomic_operations == NULL )
277     {
278         msg_Err( p_filter, "out of memory" );
279         return -1;
280     }
281     memset ( p_data->p_overflow_buffer , 0 , p_data->i_overflow_buffer_size );
282
283     /* end */
284     return 0;
285 }
286
287 /*****************************************************************************
288  * Create: allocate headphone downmixer
289  *****************************************************************************/
290 static int Create( vlc_object_t *p_this )
291 {
292     aout_filter_t * p_filter = (aout_filter_t *)p_this;
293
294     if ( p_filter->output.i_physical_channels != ( AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT )
295           || p_filter->input.i_format != p_filter->output.i_format
296           || p_filter->input.i_rate != p_filter->output.i_rate
297           || (p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
298                && p_filter->input.i_format != VLC_FOURCC('f','i','3','2')) )
299     {
300         return -1;
301     }
302
303     /* Allocate the memory needed to store the module's structure */
304     p_filter->p_sys = malloc( sizeof(struct aout_filter_sys_t) );
305     if ( p_filter->p_sys == NULL )
306     {
307         msg_Err( p_filter, "out of memory" );
308         return -1;
309     }
310     p_filter->p_sys->i_overflow_buffer_size = 0;
311     p_filter->p_sys->p_overflow_buffer = NULL;
312     p_filter->p_sys->i_nb_atomic_operations = 0;
313     p_filter->p_sys->p_atomic_operations = NULL;
314
315     if ( Init( p_filter , p_filter->p_sys
316                 , aout_FormatNbChannels ( &p_filter->input )
317                 , p_filter->input.i_physical_channels
318                 ,  p_filter->input.i_rate ) < 0 )
319     {
320         return -1;
321     }
322
323     p_filter->pf_do_work = DoWork;
324     p_filter->b_in_place = 0;
325
326     return 0;
327 }
328
329 /*****************************************************************************
330  * Destroy: deallocate resources associated with headphone downmixer
331  *****************************************************************************/
332 static void Destroy( vlc_object_t *p_this )
333 {
334     aout_filter_t * p_filter = (aout_filter_t *)p_this;
335
336     if ( p_filter->p_sys != NULL )
337     {
338         if ( p_filter->p_sys->p_overflow_buffer != NULL )
339         {
340             free ( p_filter->p_sys->p_overflow_buffer );
341         }
342         if ( p_filter->p_sys->p_atomic_operations != NULL )
343         {
344             free ( p_filter->p_sys->p_atomic_operations );
345         }
346         free ( p_filter->p_sys );
347         p_filter->p_sys = NULL;
348     }
349 }
350
351 /*****************************************************************************
352  * DoWork: convert a buffer
353  *****************************************************************************/
354 static void DoWork( aout_instance_t * p_aout, aout_filter_t * p_filter,
355                     aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
356 {
357     int i_input_nb = aout_FormatNbChannels( &p_filter->input );
358     int i_output_nb = aout_FormatNbChannels( &p_filter->output );
359
360     float * p_in = (float*) p_in_buf->p_buffer;
361     byte_t * p_out;
362     byte_t * p_overflow;
363     byte_t * p_slide;
364
365     size_t i_overflow_size;/* in bytes */
366     size_t i_out_size;/* in bytes */
367
368     unsigned int i, j;
369
370     int i_source_channel_offset;
371     int i_dest_channel_offset;
372     unsigned int i_delay;
373     double d_amplitude_factor;
374
375
376     /* out buffer characterisitcs */
377     p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
378     p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * i_output_nb / i_input_nb;
379     p_out = p_out_buf->p_buffer;
380     i_out_size = p_out_buf->i_nb_bytes;
381
382     if ( p_filter->p_sys != NULL )
383     {
384         /* Slide the overflow buffer */
385         p_overflow = p_filter->p_sys->p_overflow_buffer;
386         i_overflow_size = p_filter->p_sys->i_overflow_buffer_size;
387
388         memset ( p_out , 0 , i_out_size );
389         if ( i_out_size > i_overflow_size )
390             memcpy ( p_out , p_overflow , i_overflow_size );
391         else
392             memcpy ( p_out , p_overflow , i_out_size );
393
394         p_slide = p_filter->p_sys->p_overflow_buffer;
395         while ( p_slide < p_overflow + i_overflow_size )
396         {
397             if ( p_slide + i_out_size < p_overflow + i_overflow_size )
398             {
399                 memset ( p_slide , 0 , i_out_size );
400                 if ( p_slide + 2 * i_out_size < p_overflow + i_overflow_size )
401                     memcpy ( p_slide , p_slide + i_out_size , i_out_size );
402                 else
403                     memcpy ( p_slide , p_slide + i_out_size
404                       , p_overflow + i_overflow_size - ( p_slide + i_out_size ) );
405             }
406             else
407             {
408                 memset ( p_slide , 0 , p_overflow + i_overflow_size - p_slide );
409             }
410             p_slide += i_out_size;
411         }
412
413         /* apply the atomic operations */
414         for ( i = 0 ; i < p_filter->p_sys->i_nb_atomic_operations ; i++ )
415         {
416             /* shorter variable names */
417             i_source_channel_offset
418                 = p_filter->p_sys->p_atomic_operations[i].i_source_channel_offset;
419             i_dest_channel_offset
420                 = p_filter->p_sys->p_atomic_operations[i].i_dest_channel_offset;
421             i_delay = p_filter->p_sys->p_atomic_operations[i].i_delay;
422             d_amplitude_factor
423                 = p_filter->p_sys->p_atomic_operations[i].d_amplitude_factor;
424
425             if ( p_out_buf->i_nb_samples > i_delay )
426             {
427                 /* current buffer coefficients */
428                 for ( j = 0 ; j < p_out_buf->i_nb_samples - i_delay ; j++ )
429                 {
430                     ((float*)p_out)[ (i_delay+j)*i_output_nb + i_dest_channel_offset ]
431                         += p_in[ j * i_input_nb + i_source_channel_offset ]
432                            * d_amplitude_factor;
433                 }
434
435                 /* overflow buffer coefficients */
436                 for ( j = 0 ; j < i_delay ; j++ )
437                 {
438                     ((float*)p_overflow)[ j*i_output_nb + i_dest_channel_offset ]
439                         += p_in[ (p_out_buf->i_nb_samples - i_delay + j)
440                            * i_input_nb + i_source_channel_offset ]
441                            * d_amplitude_factor;
442                 }
443             }
444             else
445             {
446                 /* overflow buffer coefficients only */
447                 for ( j = 0 ; j < p_out_buf->i_nb_samples ; j++ )
448                 {
449                     ((float*)p_overflow)[ (i_delay - p_out_buf->i_nb_samples + j)
450                         * i_output_nb + i_dest_channel_offset ]
451                         += p_in[ j * i_input_nb + i_source_channel_offset ]
452                            * d_amplitude_factor;
453                 }
454             }
455         }
456     }
457     else
458     {
459         memset ( p_out , 0 , i_out_size );
460     }
461 }