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, NULL, HEADPHONE_DIM_TEXT,
82 HEADPHONE_DIM_LONGTEXT, false )
83 add_bool( "headphone-compensate", false, NULL, HEADPHONE_COMPENSATE_TEXT,
84 HEADPHONE_COMPENSATE_LONGTEXT, true )
85 add_bool( "headphone-dolby", false, NULL, 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 uint8_t * 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_InheritInteger( 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 = 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 aout_buffer_t * p_in_buf, aout_buffer_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;
344 size_t i_overflow_size; /* in bytes */
345 size_t i_out_size; /* in bytes */
349 int i_source_channel_offset;
350 int i_dest_channel_offset;
351 unsigned int i_delay;
352 double d_amplitude_factor;
354 /* out buffer characterisitcs */
355 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
356 p_out_buf->i_buffer = p_in_buf->i_buffer * i_output_nb / i_input_nb;
357 p_out = p_out_buf->p_buffer;
358 i_out_size = p_out_buf->i_buffer;
360 /* Slide the overflow buffer */
361 p_overflow = p_sys->p_overflow_buffer;
362 i_overflow_size = p_sys->i_overflow_buffer_size;
364 memset( p_out, 0, i_out_size );
365 if ( i_out_size > i_overflow_size )
366 memcpy( p_out, p_overflow, i_overflow_size );
368 memcpy( p_out, p_overflow, i_out_size );
370 p_slide = p_sys->p_overflow_buffer;
371 while( p_slide < p_overflow + i_overflow_size )
373 if( p_slide + i_out_size < p_overflow + i_overflow_size )
375 memset( p_slide, 0, i_out_size );
376 if( p_slide + 2 * i_out_size < p_overflow + i_overflow_size )
377 memcpy( p_slide, p_slide + i_out_size, i_out_size );
379 memcpy( p_slide, p_slide + i_out_size,
380 p_overflow + i_overflow_size - ( p_slide + i_out_size ) );
384 memset( p_slide, 0, p_overflow + i_overflow_size - p_slide );
386 p_slide += i_out_size;
389 /* apply the atomic operations */
390 for( i = 0; i < p_sys->i_nb_atomic_operations; i++ )
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;
399 = p_sys->p_atomic_operations[i].d_amplitude_factor;
401 if( p_out_buf->i_nb_samples > i_delay )
403 /* current buffer coefficients */
404 for( j = 0; j < p_out_buf->i_nb_samples - i_delay; j++ )
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;
411 /* overflow buffer coefficients */
412 for( j = 0; j < i_delay; j++ )
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;
422 /* overflow buffer coefficients only */
423 for( j = 0; j < p_out_buf->i_nb_samples; j++ )
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;
437 /*****************************************************************************
439 *****************************************************************************/
440 static int OpenFilter( vlc_object_t *p_this )
442 filter_t *p_filter = (filter_t *)p_this;
446 /* Activate this filter only with stereo devices */
447 if( p_filter->fmt_out.audio.i_physical_channels
448 != (AOUT_CHAN_LEFT|AOUT_CHAN_RIGHT) )
450 msg_Dbg( p_filter, "filter discarded (incompatible format)" );
454 /* Request a specific format if not already compatible */
455 if( p_filter->fmt_in.audio.i_original_channels
456 != p_filter->fmt_out.audio.i_original_channels )
459 p_filter->fmt_in.audio.i_original_channels =
460 p_filter->fmt_out.audio.i_original_channels;
462 if( p_filter->fmt_in.audio.i_format != VLC_CODEC_FL32
463 || p_filter->fmt_out.audio.i_format != VLC_CODEC_FL32 )
466 p_filter->fmt_in.audio.i_format = VLC_CODEC_FL32;
467 p_filter->fmt_out.audio.i_format = VLC_CODEC_FL32;
469 if( p_filter->fmt_in.audio.i_rate != p_filter->fmt_out.audio.i_rate )
472 p_filter->fmt_in.audio.i_rate = p_filter->fmt_out.audio.i_rate;
474 if( p_filter->fmt_in.audio.i_physical_channels == (AOUT_CHAN_LEFT|AOUT_CHAN_RIGHT)
475 && ( p_filter->fmt_in.audio.i_original_channels & AOUT_CHAN_DOLBYSTEREO )
476 && !var_InheritInteger( p_filter, "headphone-dolby" ) )
479 p_filter->fmt_in.audio.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
486 msg_Dbg( p_filter, "requesting specific format" );
490 /* Allocate the memory needed to store the module's structure */
491 p_sys = p_filter->p_sys = malloc( sizeof(struct filter_sys_t) );
494 p_sys->i_overflow_buffer_size = 0;
495 p_sys->p_overflow_buffer = NULL;
496 p_sys->i_nb_atomic_operations = 0;
497 p_sys->p_atomic_operations = NULL;
499 if( Init( VLC_OBJECT(p_filter), p_sys
500 , aout_FormatNbChannels ( &(p_filter->fmt_in.audio) )
501 , p_filter->fmt_in.audio.i_physical_channels
502 , p_filter->fmt_in.audio.i_rate ) < 0 )
508 p_filter->pf_audio_filter = Convert;
509 p_filter->fmt_out.audio.i_rate = p_filter->fmt_in.audio.i_rate;
514 /*****************************************************************************
515 * CloseFilter : deallocate data structures
516 *****************************************************************************/
517 static void CloseFilter( vlc_object_t *p_this )
519 filter_t *p_filter = (filter_t *)p_this;
521 free( p_filter->p_sys->p_overflow_buffer );
522 free( p_filter->p_sys->p_atomic_operations );
523 free( p_filter->p_sys );
526 static block_t *Convert( filter_t *p_filter, block_t *p_block )
528 if( !p_block || !p_block->i_nb_samples )
531 block_Release( p_block );
535 size_t i_out_size = p_block->i_nb_samples *
536 p_filter->fmt_out.audio.i_bitspersample/8 *
537 aout_FormatNbChannels( &(p_filter->fmt_out.audio) );
539 block_t *p_out = filter_NewAudioBuffer( p_filter, i_out_size );
542 msg_Warn( p_filter, "can't get output buffer" );
543 block_Release( p_block );
547 p_out->i_nb_samples = p_block->i_nb_samples;
548 p_out->i_dts = p_block->i_dts;
549 p_out->i_pts = p_block->i_pts;
550 p_out->i_length = p_block->i_length;
552 DoWork( p_filter, p_block, p_out );
554 block_Release( p_block );