00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <stdlib.h>
00029 #include <string.h>
00030 #include <math.h>
00031
00032 #include <vlc/vlc.h>
00033 #include "audio_output.h"
00034 #include "aout_internal.h"
00035
00036
00037
00038
00039 static int Create ( vlc_object_t * );
00040 static void Destroy ( vlc_object_t * );
00041
00042 static void DoWork ( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
00043 aout_buffer_t * );
00044
00045
00046
00047
00048 #define MODULE_DESCRIPTION N_ ( \
00049 "This effect gives you the feeling that you are standing in a room " \
00050 "with a complete 7.1 speaker set when using only a headphone, " \
00051 "providing a more realistic sound experience. It should also be " \
00052 "more comfortable and less tiring when listening to music for " \
00053 "long periods of time.\nIt works with any source format from mono " \
00054 "to 7.1.")
00055
00056 #define HEADPHONE_DIM_TEXT N_("Characteristic dimension")
00057 #define HEADPHONE_DIM_LONGTEXT N_( \
00058 "Distance between front left speaker and listener in meters.")
00059
00060 #define HEADPHONE_COMPENSATE_TEXT N_("Compensate delay")
00061 #define HEADPHONE_COMPENSATE_LONGTEXT N_( \
00062 "The delay which is introduced by the physical algorithm may "\
00063 "sometimes be disturbing for the lipsync. In that case, turn "\
00064 "this on to compensate.")
00065
00066 #define HEADPHONE_DOLBY_TEXT N_("No decoding of Dolby Surround")
00067 #define HEADPHONE_DOLBY_LONGTEXT N_( \
00068 "If this option is turned on (not recommended), Dolby Surround "\
00069 "encoded streams won't be decoded before being processed by this "\
00070 "filter.")
00071
00072 vlc_module_begin();
00073 set_description( N_("Headphone channel mixer with virtual spatialization effect") );
00074 set_shortname( _("Headphone effect") );
00075 set_category( CAT_AUDIO );
00076 set_subcategory( SUBCAT_AUDIO_AFILTER );
00077
00078 add_integer( "headphone-dim", 10, NULL, HEADPHONE_DIM_TEXT,
00079 HEADPHONE_DIM_LONGTEXT, VLC_FALSE );
00080 add_bool( "headphone-compensate", 0, NULL, HEADPHONE_COMPENSATE_TEXT,
00081 HEADPHONE_COMPENSATE_LONGTEXT, VLC_TRUE );
00082 add_bool( "headphone-dolby", 0, NULL, HEADPHONE_DOLBY_TEXT,
00083 HEADPHONE_DOLBY_LONGTEXT, VLC_TRUE );
00084
00085 set_capability( "audio filter", 0 );
00086 set_callbacks( Create, Destroy );
00087 add_shortcut( "headphone" );
00088 vlc_module_end();
00089
00090
00091
00092
00093
00094 struct atomic_operation_t
00095 {
00096 int i_source_channel_offset;
00097 int i_dest_channel_offset;
00098 unsigned int i_delay;
00099 double d_amplitude_factor;
00100 };
00101
00102 struct aout_filter_sys_t
00103 {
00104 size_t i_overflow_buffer_size;
00105 byte_t * p_overflow_buffer;
00106 unsigned int i_nb_atomic_operations;
00107 struct atomic_operation_t * p_atomic_operations;
00108 };
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128 static void ComputeChannelOperations ( struct aout_filter_sys_t * p_data
00129 , unsigned int i_rate , unsigned int i_next_atomic_operation
00130 , int i_source_channel_offset , double d_x , double d_z
00131 , double d_compensation_length , double d_channel_amplitude_factor )
00132 {
00133 double d_c = 340;
00134 double d_compensation_delay = (d_compensation_length-0.1) / d_c * i_rate;
00135
00136
00137 p_data->p_atomic_operations[i_next_atomic_operation]
00138 .i_source_channel_offset = i_source_channel_offset;
00139 p_data->p_atomic_operations[i_next_atomic_operation]
00140 .i_dest_channel_offset = 0;
00141 p_data->p_atomic_operations[i_next_atomic_operation]
00142 .i_delay = (int)( sqrt( (-0.1-d_x)*(-0.1-d_x) + (0-d_z)*(0-d_z) )
00143 / d_c * i_rate - d_compensation_delay );
00144 if ( d_x < 0 )
00145 {
00146 p_data->p_atomic_operations[i_next_atomic_operation]
00147 .d_amplitude_factor = d_channel_amplitude_factor * 1.1 / 2;
00148 }
00149 else if ( d_x > 0 )
00150 {
00151 p_data->p_atomic_operations[i_next_atomic_operation]
00152 .d_amplitude_factor = d_channel_amplitude_factor * 0.9 / 2;
00153 }
00154 else
00155 {
00156 p_data->p_atomic_operations[i_next_atomic_operation]
00157 .d_amplitude_factor = d_channel_amplitude_factor / 2;
00158 }
00159
00160
00161 p_data->p_atomic_operations[i_next_atomic_operation + 1]
00162 .i_source_channel_offset = i_source_channel_offset;
00163 p_data->p_atomic_operations[i_next_atomic_operation + 1]
00164 .i_dest_channel_offset = 1;
00165 p_data->p_atomic_operations[i_next_atomic_operation + 1]
00166 .i_delay = (int)( sqrt( (0.1-d_x)*(0.1-d_x) + (0-d_z)*(0-d_z) )
00167 / d_c * i_rate - d_compensation_delay );
00168 if ( d_x < 0 )
00169 {
00170 p_data->p_atomic_operations[i_next_atomic_operation + 1]
00171 .d_amplitude_factor = d_channel_amplitude_factor * 0.9 / 2;
00172 }
00173 else if ( d_x > 0 )
00174 {
00175 p_data->p_atomic_operations[i_next_atomic_operation + 1]
00176 .d_amplitude_factor = d_channel_amplitude_factor * 1.1 / 2;
00177 }
00178 else
00179 {
00180 p_data->p_atomic_operations[i_next_atomic_operation + 1]
00181 .d_amplitude_factor = d_channel_amplitude_factor / 2;
00182 }
00183 }
00184
00185 static int Init ( aout_filter_t * p_filter , struct aout_filter_sys_t * p_data
00186 , unsigned int i_nb_channels , uint32_t i_physical_channels
00187 , unsigned int i_rate )
00188 {
00189 double d_x = config_GetInt ( p_filter , "headphone-dim" );
00190 double d_z = d_x;
00191 double d_z_rear = -d_x/3;
00192 double d_min = 0;
00193 unsigned int i_next_atomic_operation;
00194 int i_source_channel_offset;
00195 unsigned int i;
00196
00197 if ( p_data == NULL )
00198 {
00199 msg_Dbg ( p_filter, "passing a null pointer as argument" );
00200 return 0;
00201 }
00202
00203 if ( config_GetInt ( p_filter , "headphone-compensate" ) )
00204 {
00205
00206 if ( i_physical_channels & AOUT_CHAN_REARCENTER )
00207 {
00208 d_min = d_z_rear;
00209 }
00210 else
00211 {
00212 d_min = d_z;
00213 }
00214 }
00215
00216
00217 p_data->i_nb_atomic_operations = i_nb_channels * 2;
00218 if ( i_physical_channels & AOUT_CHAN_CENTER )
00219 {
00220 p_data->i_nb_atomic_operations += 2;
00221 }
00222 p_data->p_atomic_operations = malloc ( sizeof(struct atomic_operation_t)
00223 * p_data->i_nb_atomic_operations );
00224 if ( p_data->p_atomic_operations == NULL )
00225 {
00226 msg_Err( p_filter, "out of memory" );
00227 return -1;
00228 }
00229
00230
00231
00232 i_next_atomic_operation = 0;
00233 i_source_channel_offset = 0;
00234 if ( i_physical_channels & AOUT_CHAN_LEFT )
00235 {
00236 ComputeChannelOperations ( p_data , i_rate
00237 , i_next_atomic_operation , i_source_channel_offset
00238 , -d_x , d_z , d_min , 2.0 / i_nb_channels );
00239 i_next_atomic_operation += 2;
00240 i_source_channel_offset++;
00241 }
00242 if ( i_physical_channels & AOUT_CHAN_RIGHT )
00243 {
00244 ComputeChannelOperations ( p_data , i_rate
00245 , i_next_atomic_operation , i_source_channel_offset
00246 , d_x , d_z , d_min , 2.0 / i_nb_channels );
00247 i_next_atomic_operation += 2;
00248 i_source_channel_offset++;
00249 }
00250 if ( i_physical_channels & AOUT_CHAN_MIDDLELEFT )
00251 {
00252 ComputeChannelOperations ( p_data , i_rate
00253 , i_next_atomic_operation , i_source_channel_offset
00254 , -d_x , 0 , d_min , 1.5 / i_nb_channels );
00255 i_next_atomic_operation += 2;
00256 i_source_channel_offset++;
00257 }
00258 if ( i_physical_channels & AOUT_CHAN_MIDDLERIGHT )
00259 {
00260 ComputeChannelOperations ( p_data , i_rate
00261 , i_next_atomic_operation , i_source_channel_offset
00262 , d_x , 0 , d_min , 1.5 / i_nb_channels );
00263 i_next_atomic_operation += 2;
00264 i_source_channel_offset++;
00265 }
00266 if ( i_physical_channels & AOUT_CHAN_REARLEFT )
00267 {
00268 ComputeChannelOperations ( p_data , i_rate
00269 , i_next_atomic_operation , i_source_channel_offset
00270 , -d_x , d_z_rear , d_min , 1.5 / i_nb_channels );
00271 i_next_atomic_operation += 2;
00272 i_source_channel_offset++;
00273 }
00274 if ( i_physical_channels & AOUT_CHAN_REARRIGHT )
00275 {
00276 ComputeChannelOperations ( p_data , i_rate
00277 , i_next_atomic_operation , i_source_channel_offset
00278 , d_x , d_z_rear , d_min , 1.5 / i_nb_channels );
00279 i_next_atomic_operation += 2;
00280 i_source_channel_offset++;
00281 }
00282 if ( i_physical_channels & AOUT_CHAN_REARCENTER )
00283 {
00284 ComputeChannelOperations ( p_data , i_rate
00285 , i_next_atomic_operation , i_source_channel_offset
00286 , 0 , -d_z , d_min , 1.5 / i_nb_channels );
00287 i_next_atomic_operation += 2;
00288 i_source_channel_offset++;
00289 }
00290 if ( i_physical_channels & AOUT_CHAN_CENTER )
00291 {
00292
00293 ComputeChannelOperations ( p_data , i_rate
00294 , i_next_atomic_operation , i_source_channel_offset
00295 , d_x / 5.0 , d_z , d_min , 0.75 / i_nb_channels );
00296 i_next_atomic_operation += 2;
00297 ComputeChannelOperations ( p_data , i_rate
00298 , i_next_atomic_operation , i_source_channel_offset
00299 , -d_x / 5.0 , d_z , d_min , 0.75 / i_nb_channels );
00300 i_next_atomic_operation += 2;
00301 i_source_channel_offset++;
00302 }
00303 if ( i_physical_channels & AOUT_CHAN_LFE )
00304 {
00305 ComputeChannelOperations ( p_data , i_rate
00306 , i_next_atomic_operation , i_source_channel_offset
00307 , 0 , d_z_rear , d_min , 5.0 / i_nb_channels );
00308 i_next_atomic_operation += 2;
00309 i_source_channel_offset++;
00310 }
00311
00312
00313
00314 p_data->i_overflow_buffer_size = 0;
00315 for ( i = 0 ; i < p_data->i_nb_atomic_operations ; i++ )
00316 {
00317 if ( p_data->i_overflow_buffer_size
00318 < p_data->p_atomic_operations[i].i_delay * 2 * sizeof (float) )
00319 {
00320 p_data->i_overflow_buffer_size
00321 = p_data->p_atomic_operations[i].i_delay * 2 * sizeof (float);
00322 }
00323 }
00324 p_data->p_overflow_buffer = malloc ( p_data->i_overflow_buffer_size );
00325 if ( p_data->p_atomic_operations == NULL )
00326 {
00327 msg_Err( p_filter, "out of memory" );
00328 return -1;
00329 }
00330 memset ( p_data->p_overflow_buffer , 0 , p_data->i_overflow_buffer_size );
00331
00332
00333 return 0;
00334 }
00335
00336
00337
00338
00339 static int Create( vlc_object_t *p_this )
00340 {
00341 aout_filter_t * p_filter = (aout_filter_t *)p_this;
00342 vlc_bool_t b_fit = VLC_TRUE;
00343
00344
00345 if ( p_filter->output.i_physical_channels
00346 != (AOUT_CHAN_LEFT|AOUT_CHAN_RIGHT) )
00347 {
00348 msg_Dbg( p_filter, "Filter discarded (incompatible format)" );
00349 return VLC_EGENERIC;
00350 }
00351
00352
00353 if ( p_filter->input.i_original_channels
00354 != p_filter->output.i_original_channels )
00355 {
00356 b_fit = VLC_FALSE;
00357 p_filter->input.i_original_channels =
00358 p_filter->output.i_original_channels;
00359 }
00360 if ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
00361 || p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
00362 {
00363 b_fit = VLC_FALSE;
00364 p_filter->input.i_format = VLC_FOURCC('f','l','3','2');
00365 p_filter->output.i_format = VLC_FOURCC('f','l','3','2');
00366 }
00367 if ( p_filter->input.i_rate != p_filter->output.i_rate )
00368 {
00369 b_fit = VLC_FALSE;
00370 p_filter->input.i_rate = p_filter->output.i_rate;
00371 }
00372 if ( p_filter->input.i_physical_channels == (AOUT_CHAN_LEFT|AOUT_CHAN_RIGHT)
00373 && ( p_filter->input.i_original_channels & AOUT_CHAN_DOLBYSTEREO )
00374 && ! config_GetInt ( p_filter , "headphone-dolby" ) )
00375 {
00376 b_fit = VLC_FALSE;
00377 p_filter->input.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
00378 AOUT_CHAN_CENTER |
00379 AOUT_CHAN_REARLEFT |
00380 AOUT_CHAN_REARRIGHT;
00381 }
00382 if ( ! b_fit )
00383 {
00384 msg_Dbg( p_filter, "Requesting specific format" );
00385 return VLC_EGENERIC;
00386 }
00387
00388
00389 p_filter->p_sys = malloc( sizeof(struct aout_filter_sys_t) );
00390 if ( p_filter->p_sys == NULL )
00391 {
00392 msg_Err( p_filter, "Out of memory" );
00393 return VLC_EGENERIC;
00394 }
00395 p_filter->p_sys->i_overflow_buffer_size = 0;
00396 p_filter->p_sys->p_overflow_buffer = NULL;
00397 p_filter->p_sys->i_nb_atomic_operations = 0;
00398 p_filter->p_sys->p_atomic_operations = NULL;
00399
00400 if ( Init( p_filter , p_filter->p_sys
00401 , aout_FormatNbChannels ( &p_filter->input )
00402 , p_filter->input.i_physical_channels
00403 , p_filter->input.i_rate ) < 0 )
00404 {
00405 return VLC_EGENERIC;
00406 }
00407
00408 p_filter->pf_do_work = DoWork;
00409 p_filter->b_in_place = 0;
00410
00411 return VLC_SUCCESS;
00412 }
00413
00414
00415
00416
00417 static void Destroy( vlc_object_t *p_this )
00418 {
00419 aout_filter_t * p_filter = (aout_filter_t *)p_this;
00420
00421 if ( p_filter->p_sys != NULL )
00422 {
00423 if ( p_filter->p_sys->p_overflow_buffer != NULL )
00424 {
00425 free ( p_filter->p_sys->p_overflow_buffer );
00426 }
00427 if ( p_filter->p_sys->p_atomic_operations != NULL )
00428 {
00429 free ( p_filter->p_sys->p_atomic_operations );
00430 }
00431 free ( p_filter->p_sys );
00432 p_filter->p_sys = NULL;
00433 }
00434 }
00435
00436
00437
00438
00439 static void DoWork( aout_instance_t * p_aout, aout_filter_t * p_filter,
00440 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
00441 {
00442 int i_input_nb = aout_FormatNbChannels( &p_filter->input );
00443 int i_output_nb = aout_FormatNbChannels( &p_filter->output );
00444
00445 float * p_in = (float*) p_in_buf->p_buffer;
00446 byte_t * p_out;
00447 byte_t * p_overflow;
00448 byte_t * p_slide;
00449
00450 size_t i_overflow_size;
00451 size_t i_out_size;
00452
00453 unsigned int i, j;
00454
00455 int i_source_channel_offset;
00456 int i_dest_channel_offset;
00457 unsigned int i_delay;
00458 double d_amplitude_factor;
00459
00460
00461
00462 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
00463 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * i_output_nb / i_input_nb;
00464 p_out = p_out_buf->p_buffer;
00465 i_out_size = p_out_buf->i_nb_bytes;
00466
00467 if ( p_filter->p_sys != NULL )
00468 {
00469
00470 p_overflow = p_filter->p_sys->p_overflow_buffer;
00471 i_overflow_size = p_filter->p_sys->i_overflow_buffer_size;
00472
00473 memset ( p_out , 0 , i_out_size );
00474 if ( i_out_size > i_overflow_size )
00475 memcpy ( p_out , p_overflow , i_overflow_size );
00476 else
00477 memcpy ( p_out , p_overflow , i_out_size );
00478
00479 p_slide = p_filter->p_sys->p_overflow_buffer;
00480 while ( p_slide < p_overflow + i_overflow_size )
00481 {
00482 if ( p_slide + i_out_size < p_overflow + i_overflow_size )
00483 {
00484 memset ( p_slide , 0 , i_out_size );
00485 if ( p_slide + 2 * i_out_size < p_overflow + i_overflow_size )
00486 memcpy ( p_slide , p_slide + i_out_size , i_out_size );
00487 else
00488 memcpy ( p_slide , p_slide + i_out_size
00489 , p_overflow + i_overflow_size - ( p_slide + i_out_size ) );
00490 }
00491 else
00492 {
00493 memset ( p_slide , 0 , p_overflow + i_overflow_size - p_slide );
00494 }
00495 p_slide += i_out_size;
00496 }
00497
00498
00499 for ( i = 0 ; i < p_filter->p_sys->i_nb_atomic_operations ; i++ )
00500 {
00501
00502 i_source_channel_offset
00503 = p_filter->p_sys->p_atomic_operations[i].i_source_channel_offset;
00504 i_dest_channel_offset
00505 = p_filter->p_sys->p_atomic_operations[i].i_dest_channel_offset;
00506 i_delay = p_filter->p_sys->p_atomic_operations[i].i_delay;
00507 d_amplitude_factor
00508 = p_filter->p_sys->p_atomic_operations[i].d_amplitude_factor;
00509
00510 if ( p_out_buf->i_nb_samples > i_delay )
00511 {
00512
00513 for ( j = 0 ; j < p_out_buf->i_nb_samples - i_delay ; j++ )
00514 {
00515 ((float*)p_out)[ (i_delay+j)*i_output_nb + i_dest_channel_offset ]
00516 += p_in[ j * i_input_nb + i_source_channel_offset ]
00517 * d_amplitude_factor;
00518 }
00519
00520
00521 for ( j = 0 ; j < i_delay ; j++ )
00522 {
00523 ((float*)p_overflow)[ j*i_output_nb + i_dest_channel_offset ]
00524 += p_in[ (p_out_buf->i_nb_samples - i_delay + j)
00525 * i_input_nb + i_source_channel_offset ]
00526 * d_amplitude_factor;
00527 }
00528 }
00529 else
00530 {
00531
00532 for ( j = 0 ; j < p_out_buf->i_nb_samples ; j++ )
00533 {
00534 ((float*)p_overflow)[ (i_delay - p_out_buf->i_nb_samples + j)
00535 * i_output_nb + i_dest_channel_offset ]
00536 += p_in[ j * i_input_nb + i_source_channel_offset ]
00537 * d_amplitude_factor;
00538 }
00539 }
00540 }
00541 }
00542 else
00543 {
00544 memset ( p_out , 0 , i_out_size );
00545 }
00546 }