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
8 * Authors: Boris Dorès <babal@via.ecp.fr>
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)
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
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 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
33 #include <math.h> /* sqrt */
35 #include <vlc_common.h>
36 #include <vlc_plugin.h>
38 #include <vlc_filter.h>
39 #include <vlc_block.h>
41 /*****************************************************************************
43 *****************************************************************************/
44 static int OpenFilter ( vlc_object_t * );
45 static void CloseFilter( vlc_object_t * );
46 static block_t *Convert( filter_t *, block_t * );
48 /*****************************************************************************
50 *****************************************************************************/
51 #define MODULE_DESCRIPTION N_ ( \
52 "This effect gives you the feeling that you are standing in a room " \
53 "with a complete 7.1 speaker set when using only a headphone, " \
54 "providing a more realistic sound experience. It should also be " \
55 "more comfortable and less tiring when listening to music for " \
56 "long periods of time.\nIt works with any source format from mono " \
59 #define HEADPHONE_DIM_TEXT N_("Characteristic dimension")
60 #define HEADPHONE_DIM_LONGTEXT N_( \
61 "Distance between front left speaker and listener in meters.")
63 #define HEADPHONE_COMPENSATE_TEXT N_("Compensate delay")
64 #define HEADPHONE_COMPENSATE_LONGTEXT N_( \
65 "The delay which is introduced by the physical algorithm may "\
66 "sometimes be disturbing for the synchronization between lips-movement "\
67 "and speech. In case, turn this on to compensate.")
69 #define HEADPHONE_DOLBY_TEXT N_("No decoding of Dolby Surround")
70 #define HEADPHONE_DOLBY_LONGTEXT N_( \
71 "Dolby Surround encoded streams won't be decoded before being " \
72 "processed by this filter. Enabling this setting is not recommended.")
75 set_description( N_("Headphone virtual spatialization effect") )
76 set_shortname( N_("Headphone effect") )
77 set_help( MODULE_DESCRIPTION )
78 set_category( CAT_AUDIO )
79 set_subcategory( SUBCAT_AUDIO_AFILTER )
81 add_integer( "headphone-dim", 10, HEADPHONE_DIM_TEXT,
82 HEADPHONE_DIM_LONGTEXT, false )
83 add_bool( "headphone-compensate", false, HEADPHONE_COMPENSATE_TEXT,
84 HEADPHONE_COMPENSATE_LONGTEXT, true )
85 add_bool( "headphone-dolby", false, HEADPHONE_DOLBY_TEXT,
86 HEADPHONE_DOLBY_LONGTEXT, true )
88 set_capability( "audio filter", 0 )
89 set_callbacks( OpenFilter, CloseFilter )
90 add_shortcut( "headphone" )
94 /*****************************************************************************
95 * Internal data structures
96 *****************************************************************************/
97 struct atomic_operation_t
99 int i_source_channel_offset;
100 int i_dest_channel_offset;
101 unsigned int i_delay;/* in sample unit */
102 double d_amplitude_factor;
107 size_t i_overflow_buffer_size;/* in bytes */
108 float * p_overflow_buffer;
109 unsigned int i_nb_atomic_operations;
110 struct atomic_operation_t * p_atomic_operations;
113 /*****************************************************************************
114 * Init: initialize internal data structures
115 * and computes the needed atomic operations
116 *****************************************************************************/
117 /* x and z represent the coordinates of the virtual speaker
118 * relatively to the center of the listener's head, measured in meters :
127 * rear left rear right
131 static void ComputeChannelOperations( struct filter_sys_t * p_data
132 , unsigned int i_rate, unsigned int i_next_atomic_operation
133 , int i_source_channel_offset, double d_x, double d_z
134 , double d_compensation_length, double d_channel_amplitude_factor )
136 double d_c = 340; /*sound celerity (unit: m/s)*/
137 double d_compensation_delay = (d_compensation_length-0.1) / d_c * i_rate;
140 p_data->p_atomic_operations[i_next_atomic_operation]
141 .i_source_channel_offset = i_source_channel_offset;
142 p_data->p_atomic_operations[i_next_atomic_operation]
143 .i_dest_channel_offset = 0;/* left */
144 p_data->p_atomic_operations[i_next_atomic_operation]
145 .i_delay = (int)( sqrt( (-0.1-d_x)*(-0.1-d_x) + (0-d_z)*(0-d_z) )
146 / d_c * i_rate - d_compensation_delay );
149 p_data->p_atomic_operations[i_next_atomic_operation]
150 .d_amplitude_factor = d_channel_amplitude_factor * 1.1 / 2;
154 p_data->p_atomic_operations[i_next_atomic_operation]
155 .d_amplitude_factor = d_channel_amplitude_factor * 0.9 / 2;
159 p_data->p_atomic_operations[i_next_atomic_operation]
160 .d_amplitude_factor = d_channel_amplitude_factor / 2;
164 p_data->p_atomic_operations[i_next_atomic_operation + 1]
165 .i_source_channel_offset = i_source_channel_offset;
166 p_data->p_atomic_operations[i_next_atomic_operation + 1]
167 .i_dest_channel_offset = 1;/* right */
168 p_data->p_atomic_operations[i_next_atomic_operation + 1]
169 .i_delay = (int)( sqrt( (0.1-d_x)*(0.1-d_x) + (0-d_z)*(0-d_z) )
170 / d_c * i_rate - d_compensation_delay );
173 p_data->p_atomic_operations[i_next_atomic_operation + 1]
174 .d_amplitude_factor = d_channel_amplitude_factor * 0.9 / 2;
178 p_data->p_atomic_operations[i_next_atomic_operation + 1]
179 .d_amplitude_factor = d_channel_amplitude_factor * 1.1 / 2;
183 p_data->p_atomic_operations[i_next_atomic_operation + 1]
184 .d_amplitude_factor = d_channel_amplitude_factor / 2;
188 static int Init( vlc_object_t *p_this, struct filter_sys_t * p_data
189 , unsigned int i_nb_channels, uint32_t i_physical_channels
190 , unsigned int i_rate )
192 double d_x = var_InheritInteger( p_this, "headphone-dim" );
194 double d_z_rear = -d_x/3;
196 unsigned int i_next_atomic_operation;
197 int i_source_channel_offset;
200 if( var_InheritBool( p_this, "headphone-compensate" ) )
202 /* minimal distance to any speaker */
203 if( i_physical_channels & AOUT_CHAN_REARCENTER )
213 /* Number of elementary operations */
214 p_data->i_nb_atomic_operations = i_nb_channels * 2;
215 if( i_physical_channels & AOUT_CHAN_CENTER )
217 p_data->i_nb_atomic_operations += 2;
219 p_data->p_atomic_operations = malloc( sizeof(struct atomic_operation_t)
220 * p_data->i_nb_atomic_operations );
221 if( p_data->p_atomic_operations == NULL )
224 /* For each virtual speaker, computes elementary wave propagation time
226 i_next_atomic_operation = 0;
227 i_source_channel_offset = 0;
228 if( i_physical_channels & AOUT_CHAN_LEFT )
230 ComputeChannelOperations( p_data , i_rate
231 , i_next_atomic_operation , i_source_channel_offset
232 , -d_x , d_z , d_min , 2.0 / i_nb_channels );
233 i_next_atomic_operation += 2;
234 i_source_channel_offset++;
236 if( i_physical_channels & AOUT_CHAN_RIGHT )
238 ComputeChannelOperations( p_data , i_rate
239 , i_next_atomic_operation , i_source_channel_offset
240 , d_x , d_z , d_min , 2.0 / i_nb_channels );
241 i_next_atomic_operation += 2;
242 i_source_channel_offset++;
244 if( i_physical_channels & AOUT_CHAN_MIDDLELEFT )
246 ComputeChannelOperations( p_data , i_rate
247 , i_next_atomic_operation , i_source_channel_offset
248 , -d_x , 0 , d_min , 1.5 / i_nb_channels );
249 i_next_atomic_operation += 2;
250 i_source_channel_offset++;
252 if( i_physical_channels & AOUT_CHAN_MIDDLERIGHT )
254 ComputeChannelOperations( p_data , i_rate
255 , i_next_atomic_operation , i_source_channel_offset
256 , d_x , 0 , d_min , 1.5 / i_nb_channels );
257 i_next_atomic_operation += 2;
258 i_source_channel_offset++;
260 if( i_physical_channels & AOUT_CHAN_REARLEFT )
262 ComputeChannelOperations( p_data , i_rate
263 , i_next_atomic_operation , i_source_channel_offset
264 , -d_x , d_z_rear , d_min , 1.5 / i_nb_channels );
265 i_next_atomic_operation += 2;
266 i_source_channel_offset++;
268 if( i_physical_channels & AOUT_CHAN_REARRIGHT )
270 ComputeChannelOperations( p_data , i_rate
271 , i_next_atomic_operation , i_source_channel_offset
272 , d_x , d_z_rear , d_min , 1.5 / i_nb_channels );
273 i_next_atomic_operation += 2;
274 i_source_channel_offset++;
276 if( i_physical_channels & AOUT_CHAN_REARCENTER )
278 ComputeChannelOperations( p_data , i_rate
279 , i_next_atomic_operation , i_source_channel_offset
280 , 0 , -d_z , d_min , 1.5 / i_nb_channels );
281 i_next_atomic_operation += 2;
282 i_source_channel_offset++;
284 if( i_physical_channels & AOUT_CHAN_CENTER )
286 /* having two center channels increases the spatialization effect */
287 ComputeChannelOperations( p_data , i_rate
288 , i_next_atomic_operation , i_source_channel_offset
289 , d_x / 5.0 , d_z , d_min , 0.75 / i_nb_channels );
290 i_next_atomic_operation += 2;
291 ComputeChannelOperations( p_data , i_rate
292 , i_next_atomic_operation , i_source_channel_offset
293 , -d_x / 5.0 , d_z , d_min , 0.75 / i_nb_channels );
294 i_next_atomic_operation += 2;
295 i_source_channel_offset++;
297 if( i_physical_channels & AOUT_CHAN_LFE )
299 ComputeChannelOperations( p_data , i_rate
300 , i_next_atomic_operation , i_source_channel_offset
301 , 0 , d_z_rear , d_min , 5.0 / i_nb_channels );
302 i_next_atomic_operation += 2;
303 i_source_channel_offset++;
306 /* Initialize the overflow buffer
307 * we need it because the process induce a delay in the samples */
308 p_data->i_overflow_buffer_size = 0;
309 for( i = 0 ; i < p_data->i_nb_atomic_operations ; i++ )
311 if( p_data->i_overflow_buffer_size
312 < p_data->p_atomic_operations[i].i_delay * 2 * sizeof (float) )
314 p_data->i_overflow_buffer_size
315 = p_data->p_atomic_operations[i].i_delay * 2 * sizeof (float);
318 p_data->p_overflow_buffer = (float *)malloc( p_data->i_overflow_buffer_size );
319 if( p_data->p_overflow_buffer == NULL )
321 free( p_data->p_atomic_operations );
324 memset( p_data->p_overflow_buffer, 0 , p_data->i_overflow_buffer_size );
329 /*****************************************************************************
330 * DoWork: convert a buffer
331 *****************************************************************************/
332 static void DoWork( filter_t * p_filter,
333 block_t * p_in_buf, block_t * p_out_buf )
335 filter_sys_t *p_sys = p_filter->p_sys;
336 int i_input_nb = aout_FormatNbChannels( &p_filter->fmt_in.audio );
337 int i_output_nb = aout_FormatNbChannels( &p_filter->fmt_out.audio );
339 float * p_in = (float*) p_in_buf->p_buffer;
341 uint8_t * p_overflow;
342 uint8_t * p_end_overflow;
345 size_t i_overflow_size; /* in bytes */
346 size_t i_out_size; /* in bytes */
350 int i_source_channel_offset;
351 int i_dest_channel_offset;
352 unsigned int i_delay;
353 double d_amplitude_factor;
355 p_out = (float *)p_out_buf->p_buffer;
356 i_out_size = p_out_buf->i_buffer;
358 /* Slide the overflow buffer */
359 p_overflow = (uint8_t *) p_sys->p_overflow_buffer;
360 i_overflow_size = p_sys->i_overflow_buffer_size;
361 p_end_overflow = p_overflow + i_overflow_size;
363 memset( p_out, 0, i_out_size );
364 memcpy( p_out, p_overflow, __MIN( i_out_size, i_overflow_size ) );
366 p_slide = (uint8_t *) p_sys->p_overflow_buffer;
367 while( p_slide < p_end_overflow )
369 size_t i_bytes_copied;
371 if( p_slide + i_out_size < p_end_overflow )
373 memset( p_slide, 0, i_out_size );
374 if( p_slide + 2 * i_out_size < p_end_overflow )
375 i_bytes_copied = i_out_size;
377 i_bytes_copied = p_end_overflow - ( p_slide + i_out_size );
378 memcpy( p_slide, p_slide + i_out_size, i_bytes_copied );
382 i_bytes_copied = p_end_overflow - p_slide;
383 memset( p_slide, 0, i_bytes_copied );
385 p_slide += i_bytes_copied;
388 /* apply the atomic operations */
389 for( i = 0; i < p_sys->i_nb_atomic_operations; i++ )
391 /* shorter variable names */
392 i_source_channel_offset
393 = p_sys->p_atomic_operations[i].i_source_channel_offset;
394 i_dest_channel_offset
395 = p_sys->p_atomic_operations[i].i_dest_channel_offset;
396 i_delay = p_sys->p_atomic_operations[i].i_delay;
398 = p_sys->p_atomic_operations[i].d_amplitude_factor;
400 if( p_out_buf->i_nb_samples > i_delay )
402 /* current buffer coefficients */
403 for( j = 0; j < p_out_buf->i_nb_samples - i_delay; j++ )
405 ((float*)p_out)[ (i_delay+j)*i_output_nb + i_dest_channel_offset ]
406 += p_in[ j * i_input_nb + i_source_channel_offset ]
407 * d_amplitude_factor;
410 /* overflow buffer coefficients */
411 for( j = 0; j < i_delay; j++ )
413 ((float*)p_overflow)[ j*i_output_nb + i_dest_channel_offset ]
414 += p_in[ (p_out_buf->i_nb_samples - i_delay + j)
415 * i_input_nb + i_source_channel_offset ]
416 * d_amplitude_factor;
421 /* overflow buffer coefficients only */
422 for( j = 0; j < p_out_buf->i_nb_samples; j++ )
424 ((float*)p_overflow)[ (i_delay - p_out_buf->i_nb_samples + j)
425 * i_output_nb + i_dest_channel_offset ]
426 += p_in[ j * i_input_nb + i_source_channel_offset ]
427 * d_amplitude_factor;
436 /*****************************************************************************
438 *****************************************************************************/
439 static int OpenFilter( vlc_object_t *p_this )
441 filter_t *p_filter = (filter_t *)p_this;
444 /* Activate this filter only with stereo devices */
445 if( p_filter->fmt_out.audio.i_physical_channels
446 != (AOUT_CHAN_LEFT|AOUT_CHAN_RIGHT) )
448 msg_Dbg( p_filter, "filter discarded (incompatible format)" );
452 /* Allocate the memory needed to store the module's structure */
453 p_sys = p_filter->p_sys = malloc( sizeof(struct filter_sys_t) );
456 p_sys->i_overflow_buffer_size = 0;
457 p_sys->p_overflow_buffer = NULL;
458 p_sys->i_nb_atomic_operations = 0;
459 p_sys->p_atomic_operations = NULL;
461 if( Init( VLC_OBJECT(p_filter), p_sys
462 , aout_FormatNbChannels ( &(p_filter->fmt_in.audio) )
463 , p_filter->fmt_in.audio.i_physical_channels
464 , p_filter->fmt_in.audio.i_rate ) < 0 )
470 /* Request a specific format if not already compatible */
471 p_filter->fmt_in.audio.i_format = VLC_CODEC_FL32;
472 p_filter->fmt_out.audio.i_format = VLC_CODEC_FL32;
473 p_filter->fmt_out.audio.i_rate = p_filter->fmt_in.audio.i_rate;
474 p_filter->fmt_in.audio.i_original_channels =
475 p_filter->fmt_out.audio.i_original_channels;
476 if( p_filter->fmt_in.audio.i_physical_channels == AOUT_CHANS_STEREO
477 && (p_filter->fmt_in.audio.i_original_channels & AOUT_CHAN_DOLBYSTEREO)
478 && !var_InheritBool( p_filter, "headphone-dolby" ) )
480 p_filter->fmt_in.audio.i_physical_channels = AOUT_CHANS_5_0;
482 p_filter->pf_audio_filter = Convert;
487 /*****************************************************************************
488 * CloseFilter : deallocate data structures
489 *****************************************************************************/
490 static void CloseFilter( vlc_object_t *p_this )
492 filter_t *p_filter = (filter_t *)p_this;
494 free( p_filter->p_sys->p_overflow_buffer );
495 free( p_filter->p_sys->p_atomic_operations );
496 free( p_filter->p_sys );
499 static block_t *Convert( filter_t *p_filter, block_t *p_block )
501 if( !p_block || !p_block->i_nb_samples )
504 block_Release( p_block );
508 size_t i_out_size = p_block->i_buffer *
509 aout_FormatNbChannels( &(p_filter->fmt_out.audio) ) /
510 aout_FormatNbChannels( &(p_filter->fmt_in.audio) );
512 block_t *p_out = block_Alloc( i_out_size );
515 msg_Warn( p_filter, "can't get output buffer" );
516 block_Release( p_block );
520 p_out->i_nb_samples = p_block->i_nb_samples;
521 p_out->i_dts = p_block->i_dts;
522 p_out->i_pts = p_block->i_pts;
523 p_out->i_length = p_block->i_length;
525 DoWork( p_filter, p_block, p_out );
527 block_Release( p_block );