]> git.sesse.net Git - vlc/blob - modules/audio_filter/channel_mixer/headphone.c
vlc_plugin: fix non-LGPL plugins meta infos
[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-2006 the VideoLAN team
6  * $Id$
7  *
8  * Authors: Boris Dorès <babal@via.ecp.fr>
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU General Public License as published by the Free
12  * Software Foundation; either version 2 of the License, or (at your option)
13  * any later version.
14  *
15  * This program is distributed in the hope that it will be useful, but WITHOUT
16  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
18  * more details.
19  *
20  * You should have received a copy of the GNU General Public License along with
21  * this program; if not, write to the Free Software Foundation, Inc., 51
22  * Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <math.h>                                        /* sqrt */
34
35 #define VLC_MODULE_LICENSE VLC_LICENSE_GPL_2_PLUS
36 #include <vlc_common.h>
37 #include <vlc_plugin.h>
38 #include <vlc_aout.h>
39 #include <vlc_filter.h>
40 #include <vlc_block.h>
41
42 /*****************************************************************************
43  * Local prototypes
44  *****************************************************************************/
45 static int  OpenFilter ( vlc_object_t * );
46 static void CloseFilter( vlc_object_t * );
47 static block_t *Convert( filter_t *, block_t * );
48
49 /*****************************************************************************
50  * Module descriptor
51  *****************************************************************************/
52 #define MODULE_DESCRIPTION N_ ( \
53      "This effect gives you the feeling that you are standing in a room " \
54      "with a complete 7.1 speaker set when using only a headphone, " \
55      "providing a more realistic sound experience. It should also be " \
56      "more comfortable and less tiring when listening to music for " \
57      "long periods of time.\nIt works with any source format from mono " \
58      "to 7.1.")
59
60 #define HEADPHONE_DIM_TEXT N_("Characteristic dimension")
61 #define HEADPHONE_DIM_LONGTEXT N_( \
62      "Distance between front left speaker and listener in meters.")
63
64 #define HEADPHONE_COMPENSATE_TEXT N_("Compensate delay")
65 #define HEADPHONE_COMPENSATE_LONGTEXT N_( \
66      "The delay which is introduced by the physical algorithm may "\
67      "sometimes be disturbing for the synchronization between lips-movement "\
68      "and speech. In case, turn this on to compensate.")
69
70 #define HEADPHONE_DOLBY_TEXT N_("No decoding of Dolby Surround")
71 #define HEADPHONE_DOLBY_LONGTEXT N_( \
72      "Dolby Surround encoded streams won't be decoded before being " \
73      "processed by this filter. Enabling this setting is not recommended.")
74
75 vlc_module_begin ()
76     set_description( N_("Headphone virtual spatialization effect") )
77     set_shortname( N_("Headphone effect") )
78     set_help( MODULE_DESCRIPTION )
79     set_category( CAT_AUDIO )
80     set_subcategory( SUBCAT_AUDIO_AFILTER )
81
82     add_integer( "headphone-dim", 10, HEADPHONE_DIM_TEXT,
83                  HEADPHONE_DIM_LONGTEXT, false )
84     add_bool( "headphone-compensate", false, HEADPHONE_COMPENSATE_TEXT,
85               HEADPHONE_COMPENSATE_LONGTEXT, true )
86     add_bool( "headphone-dolby", false, HEADPHONE_DOLBY_TEXT,
87               HEADPHONE_DOLBY_LONGTEXT, true )
88
89     set_capability( "audio filter", 0 )
90     set_callbacks( OpenFilter, CloseFilter )
91     add_shortcut( "headphone" )
92 vlc_module_end ()
93
94
95 /*****************************************************************************
96  * Internal data structures
97  *****************************************************************************/
98 struct atomic_operation_t
99 {
100     int i_source_channel_offset;
101     int i_dest_channel_offset;
102     unsigned int i_delay;/* in sample unit */
103     double d_amplitude_factor;
104 };
105
106 struct filter_sys_t
107 {
108     size_t i_overflow_buffer_size;/* in bytes */
109     float * p_overflow_buffer;
110     unsigned int i_nb_atomic_operations;
111     struct atomic_operation_t * p_atomic_operations;
112 };
113
114 /*****************************************************************************
115  * Init: initialize internal data structures
116  * and computes the needed atomic operations
117  *****************************************************************************/
118 /* x and z represent the coordinates of the virtual speaker
119  *  relatively to the center of the listener's head, measured in meters :
120  *
121  *  left              right
122  *Z
123  *-
124  *a          head
125  *x
126  *i
127  *s
128  *  rear left    rear right
129  *
130  *          x-axis
131  *  */
132 static void ComputeChannelOperations( struct filter_sys_t * p_data
133         , unsigned int i_rate, unsigned int i_next_atomic_operation
134         , int i_source_channel_offset, double d_x, double d_z
135         , double d_compensation_length, double d_channel_amplitude_factor )
136 {
137     double d_c = 340; /*sound celerity (unit: m/s)*/
138     double d_compensation_delay = (d_compensation_length-0.1) / d_c * i_rate;
139
140     /* Left ear */
141     p_data->p_atomic_operations[i_next_atomic_operation]
142         .i_source_channel_offset = i_source_channel_offset;
143     p_data->p_atomic_operations[i_next_atomic_operation]
144         .i_dest_channel_offset = 0;/* left */
145     p_data->p_atomic_operations[i_next_atomic_operation]
146         .i_delay = (int)( sqrt( (-0.1-d_x)*(-0.1-d_x) + (0-d_z)*(0-d_z) )
147                           / d_c * i_rate - d_compensation_delay );
148     if( d_x < 0 )
149     {
150         p_data->p_atomic_operations[i_next_atomic_operation]
151             .d_amplitude_factor = d_channel_amplitude_factor * 1.1 / 2;
152     }
153     else if( d_x > 0 )
154     {
155         p_data->p_atomic_operations[i_next_atomic_operation]
156             .d_amplitude_factor = d_channel_amplitude_factor * 0.9 / 2;
157     }
158     else
159     {
160         p_data->p_atomic_operations[i_next_atomic_operation]
161             .d_amplitude_factor = d_channel_amplitude_factor / 2;
162     }
163
164     /* Right ear */
165     p_data->p_atomic_operations[i_next_atomic_operation + 1]
166         .i_source_channel_offset = i_source_channel_offset;
167     p_data->p_atomic_operations[i_next_atomic_operation + 1]
168         .i_dest_channel_offset = 1;/* right */
169     p_data->p_atomic_operations[i_next_atomic_operation + 1]
170         .i_delay = (int)( sqrt( (0.1-d_x)*(0.1-d_x) + (0-d_z)*(0-d_z) )
171                           / d_c * i_rate - d_compensation_delay );
172     if( d_x < 0 )
173     {
174         p_data->p_atomic_operations[i_next_atomic_operation + 1]
175             .d_amplitude_factor = d_channel_amplitude_factor * 0.9 / 2;
176     }
177     else if( d_x > 0 )
178     {
179         p_data->p_atomic_operations[i_next_atomic_operation + 1]
180             .d_amplitude_factor = d_channel_amplitude_factor * 1.1 / 2;
181     }
182     else
183     {
184         p_data->p_atomic_operations[i_next_atomic_operation + 1]
185             .d_amplitude_factor = d_channel_amplitude_factor / 2;
186     }
187 }
188
189 static int Init( vlc_object_t *p_this, struct filter_sys_t * p_data
190         , unsigned int i_nb_channels, uint32_t i_physical_channels
191         , unsigned int i_rate )
192 {
193     double d_x = var_InheritInteger( p_this, "headphone-dim" );
194     double d_z = d_x;
195     double d_z_rear = -d_x/3;
196     double d_min = 0;
197     unsigned int i_next_atomic_operation;
198     int i_source_channel_offset;
199     unsigned int i;
200
201     if( var_InheritBool( p_this, "headphone-compensate" ) )
202     {
203         /* minimal distance to any speaker */
204         if( i_physical_channels & AOUT_CHAN_REARCENTER )
205         {
206             d_min = d_z_rear;
207         }
208         else
209         {
210             d_min = d_z;
211         }
212     }
213
214     /* Number of elementary operations */
215     p_data->i_nb_atomic_operations = i_nb_channels * 2;
216     if( i_physical_channels & AOUT_CHAN_CENTER )
217     {
218         p_data->i_nb_atomic_operations += 2;
219     }
220     p_data->p_atomic_operations = malloc( sizeof(struct atomic_operation_t)
221             * p_data->i_nb_atomic_operations );
222     if( p_data->p_atomic_operations == NULL )
223         return -1;
224
225     /* For each virtual speaker, computes elementary wave propagation time
226      * to each ear */
227     i_next_atomic_operation = 0;
228     i_source_channel_offset = 0;
229     if( i_physical_channels & AOUT_CHAN_LEFT )
230     {
231         ComputeChannelOperations( p_data , i_rate
232                 , i_next_atomic_operation , i_source_channel_offset
233                 , -d_x , d_z , d_min , 2.0 / i_nb_channels );
234         i_next_atomic_operation += 2;
235         i_source_channel_offset++;
236     }
237     if( i_physical_channels & AOUT_CHAN_RIGHT )
238     {
239         ComputeChannelOperations( p_data , i_rate
240                 , i_next_atomic_operation , i_source_channel_offset
241                 , d_x , d_z , d_min , 2.0 / i_nb_channels );
242         i_next_atomic_operation += 2;
243         i_source_channel_offset++;
244     }
245     if( i_physical_channels & AOUT_CHAN_MIDDLELEFT )
246     {
247         ComputeChannelOperations( p_data , i_rate
248                 , i_next_atomic_operation , i_source_channel_offset
249                 , -d_x , 0 , d_min , 1.5 / i_nb_channels );
250         i_next_atomic_operation += 2;
251         i_source_channel_offset++;
252     }
253     if( i_physical_channels & AOUT_CHAN_MIDDLERIGHT )
254     {
255         ComputeChannelOperations( p_data , i_rate
256                 , i_next_atomic_operation , i_source_channel_offset
257                 , d_x , 0 , d_min , 1.5 / i_nb_channels );
258         i_next_atomic_operation += 2;
259         i_source_channel_offset++;
260     }
261     if( i_physical_channels & AOUT_CHAN_REARLEFT )
262     {
263         ComputeChannelOperations( p_data , i_rate
264                 , i_next_atomic_operation , i_source_channel_offset
265                 , -d_x , d_z_rear , d_min , 1.5 / i_nb_channels );
266         i_next_atomic_operation += 2;
267         i_source_channel_offset++;
268     }
269     if( i_physical_channels & AOUT_CHAN_REARRIGHT )
270     {
271         ComputeChannelOperations( p_data , i_rate
272                 , i_next_atomic_operation , i_source_channel_offset
273                 , d_x , d_z_rear , d_min , 1.5 / i_nb_channels );
274         i_next_atomic_operation += 2;
275         i_source_channel_offset++;
276     }
277     if( i_physical_channels & AOUT_CHAN_REARCENTER )
278     {
279         ComputeChannelOperations( p_data , i_rate
280                 , i_next_atomic_operation , i_source_channel_offset
281                 , 0 , -d_z , d_min , 1.5 / i_nb_channels );
282         i_next_atomic_operation += 2;
283         i_source_channel_offset++;
284     }
285     if( i_physical_channels & AOUT_CHAN_CENTER )
286     {
287         /* having two center channels increases the spatialization effect */
288         ComputeChannelOperations( p_data , i_rate
289                 , i_next_atomic_operation , i_source_channel_offset
290                 , d_x / 5.0 , d_z , d_min , 0.75 / i_nb_channels );
291         i_next_atomic_operation += 2;
292         ComputeChannelOperations( p_data , i_rate
293                 , i_next_atomic_operation , i_source_channel_offset
294                 , -d_x / 5.0 , d_z , d_min , 0.75 / i_nb_channels );
295         i_next_atomic_operation += 2;
296         i_source_channel_offset++;
297     }
298     if( i_physical_channels & AOUT_CHAN_LFE )
299     {
300         ComputeChannelOperations( p_data , i_rate
301                 , i_next_atomic_operation , i_source_channel_offset
302                 , 0 , d_z_rear , d_min , 5.0 / i_nb_channels );
303         i_next_atomic_operation += 2;
304         i_source_channel_offset++;
305     }
306
307     /* Initialize the overflow buffer
308      * we need it because the process induce a delay in the samples */
309     p_data->i_overflow_buffer_size = 0;
310     for( i = 0 ; i < p_data->i_nb_atomic_operations ; i++ )
311     {
312         if( p_data->i_overflow_buffer_size
313                 < p_data->p_atomic_operations[i].i_delay * 2 * sizeof (float) )
314         {
315             p_data->i_overflow_buffer_size
316                 = p_data->p_atomic_operations[i].i_delay * 2 * sizeof (float);
317         }
318     }
319     p_data->p_overflow_buffer = (float *)malloc( p_data->i_overflow_buffer_size );
320     if( p_data->p_overflow_buffer == NULL )
321     {
322         free( p_data->p_atomic_operations );
323         return -1;
324     }
325     memset( p_data->p_overflow_buffer, 0 , p_data->i_overflow_buffer_size );
326
327     return 0;
328 }
329
330 /*****************************************************************************
331  * DoWork: convert a buffer
332  *****************************************************************************/
333 static void DoWork( filter_t * p_filter,
334                     block_t * p_in_buf, block_t * p_out_buf )
335 {
336     filter_sys_t *p_sys = p_filter->p_sys;
337     int i_input_nb = aout_FormatNbChannels( &p_filter->fmt_in.audio );
338     int i_output_nb = aout_FormatNbChannels( &p_filter->fmt_out.audio );
339
340     float * p_in = (float*) p_in_buf->p_buffer;
341     float * p_out;
342     uint8_t * p_overflow;
343     uint8_t * p_end_overflow;
344     uint8_t * p_slide;
345
346     size_t i_overflow_size;     /* in bytes */
347     size_t i_out_size;          /* in bytes */
348
349     unsigned int i, j;
350
351     int i_source_channel_offset;
352     int i_dest_channel_offset;
353     unsigned int i_delay;
354     double d_amplitude_factor;
355
356     p_out = (float *)p_out_buf->p_buffer;
357     i_out_size = p_out_buf->i_buffer;
358
359     /* Slide the overflow buffer */
360     p_overflow = (uint8_t *) p_sys->p_overflow_buffer;
361     i_overflow_size = p_sys->i_overflow_buffer_size;
362     p_end_overflow = p_overflow + i_overflow_size;
363
364     memset( p_out, 0, i_out_size );
365     memcpy( p_out, p_overflow, __MIN( i_out_size, i_overflow_size ) );
366
367     p_slide = (uint8_t *) p_sys->p_overflow_buffer;
368     while( p_slide < p_end_overflow )
369     {
370         size_t i_bytes_copied;
371
372         if( p_slide + i_out_size < p_end_overflow )
373         {
374             memset( p_slide, 0, i_out_size );
375             if( p_slide + 2 * i_out_size < p_end_overflow )
376                 i_bytes_copied = i_out_size;
377             else
378                 i_bytes_copied = p_end_overflow - ( p_slide + i_out_size );
379             memcpy( p_slide, p_slide + i_out_size, i_bytes_copied );
380         }
381         else
382         {
383             i_bytes_copied = p_end_overflow - p_slide;
384             memset( p_slide, 0, i_bytes_copied );
385         }
386         p_slide += i_bytes_copied;
387     }
388
389     /* apply the atomic operations */
390     for( i = 0; i < p_sys->i_nb_atomic_operations; i++ )
391     {
392         /* shorter variable names */
393         i_source_channel_offset
394             = p_sys->p_atomic_operations[i].i_source_channel_offset;
395         i_dest_channel_offset
396             = p_sys->p_atomic_operations[i].i_dest_channel_offset;
397         i_delay = p_sys->p_atomic_operations[i].i_delay;
398         d_amplitude_factor
399             = p_sys->p_atomic_operations[i].d_amplitude_factor;
400
401         if( p_out_buf->i_nb_samples > i_delay )
402         {
403             /* current buffer coefficients */
404             for( j = 0; j < p_out_buf->i_nb_samples - i_delay; j++ )
405             {
406                 ((float*)p_out)[ (i_delay+j)*i_output_nb + i_dest_channel_offset ]
407                     += p_in[ j * i_input_nb + i_source_channel_offset ]
408                        * d_amplitude_factor;
409             }
410
411             /* overflow buffer coefficients */
412             for( j = 0; j < i_delay; j++ )
413             {
414                 ((float*)p_overflow)[ j*i_output_nb + i_dest_channel_offset ]
415                     += p_in[ (p_out_buf->i_nb_samples - i_delay + j)
416                        * i_input_nb + i_source_channel_offset ]
417                        * d_amplitude_factor;
418             }
419         }
420         else
421         {
422             /* overflow buffer coefficients only */
423             for( j = 0; j < p_out_buf->i_nb_samples; j++ )
424             {
425                 ((float*)p_overflow)[ (i_delay - p_out_buf->i_nb_samples + j)
426                                         * i_output_nb + i_dest_channel_offset ]
427                     += p_in[ j * i_input_nb + i_source_channel_offset ]
428                        * d_amplitude_factor;
429             }
430         }
431     }
432 }
433
434 /*
435  * Audio filter 2
436  */
437 /*****************************************************************************
438  * OpenFilter:
439  *****************************************************************************/
440 static int OpenFilter( vlc_object_t *p_this )
441 {
442     filter_t *p_filter = (filter_t *)p_this;
443     filter_sys_t *p_sys;
444
445     /* Activate this filter only with stereo devices */
446     if( p_filter->fmt_out.audio.i_physical_channels
447             != (AOUT_CHAN_LEFT|AOUT_CHAN_RIGHT) )
448     {
449         msg_Dbg( p_filter, "filter discarded (incompatible format)" );
450         return VLC_EGENERIC;
451     }
452
453     /* Allocate the memory needed to store the module's structure */
454     p_sys = p_filter->p_sys = malloc( sizeof(struct filter_sys_t) );
455     if( p_sys == NULL )
456         return VLC_ENOMEM;
457     p_sys->i_overflow_buffer_size = 0;
458     p_sys->p_overflow_buffer = NULL;
459     p_sys->i_nb_atomic_operations = 0;
460     p_sys->p_atomic_operations = NULL;
461
462     if( Init( VLC_OBJECT(p_filter), p_sys
463                 , aout_FormatNbChannels ( &(p_filter->fmt_in.audio) )
464                 , p_filter->fmt_in.audio.i_physical_channels
465                 , p_filter->fmt_in.audio.i_rate ) < 0 )
466     {
467         free( p_sys );
468         return VLC_EGENERIC;
469     }
470
471     /* Request a specific format if not already compatible */
472     p_filter->fmt_in.audio.i_format = VLC_CODEC_FL32;
473     p_filter->fmt_out.audio.i_format = VLC_CODEC_FL32;
474     p_filter->fmt_out.audio.i_rate = p_filter->fmt_in.audio.i_rate;
475     p_filter->fmt_in.audio.i_original_channels =
476                                    p_filter->fmt_out.audio.i_original_channels;
477     if( p_filter->fmt_in.audio.i_physical_channels == AOUT_CHANS_STEREO
478      && (p_filter->fmt_in.audio.i_original_channels & AOUT_CHAN_DOLBYSTEREO)
479      && !var_InheritBool( p_filter, "headphone-dolby" ) )
480     {
481         p_filter->fmt_in.audio.i_physical_channels = AOUT_CHANS_5_0;
482     }
483     p_filter->pf_audio_filter = Convert;
484
485     return VLC_SUCCESS;
486 }
487
488 /*****************************************************************************
489  * CloseFilter : deallocate data structures
490  *****************************************************************************/
491 static void CloseFilter( vlc_object_t *p_this )
492 {
493     filter_t *p_filter = (filter_t *)p_this;
494
495     free( p_filter->p_sys->p_overflow_buffer );
496     free( p_filter->p_sys->p_atomic_operations );
497     free( p_filter->p_sys );
498 }
499
500 static block_t *Convert( filter_t *p_filter, block_t *p_block )
501 {
502     if( !p_block || !p_block->i_nb_samples )
503     {
504         if( p_block )
505             block_Release( p_block );
506         return NULL;
507     }
508
509     size_t i_out_size = p_block->i_buffer *
510         aout_FormatNbChannels( &(p_filter->fmt_out.audio) ) /
511         aout_FormatNbChannels( &(p_filter->fmt_in.audio) );
512
513     block_t *p_out = block_Alloc( i_out_size );
514     if( !p_out )
515     {
516         msg_Warn( p_filter, "can't get output buffer" );
517         block_Release( p_block );
518         return NULL;
519     }
520
521     p_out->i_nb_samples = p_block->i_nb_samples;
522     p_out->i_dts = p_block->i_dts;
523     p_out->i_pts = p_block->i_pts;
524     p_out->i_length = p_block->i_length;
525
526     DoWork( p_filter, p_block, p_out );
527
528     block_Release( p_block );
529     return p_out;
530 }