]> git.sesse.net Git - vlc/blobdiff - modules/audio_filter/channel_mixer/headphone.c
- the creation of the audio filter pipeline when specifying user audio
[vlc] / modules / audio_filter / channel_mixer / headphone.c
index ac1878a2249cb22a3ded6e9a072516921cf8d9a6..7949b4110caf3cd8cf6c17787a41d68db86cffb2 100644 (file)
@@ -2,8 +2,8 @@
  * headphone.c : headphone virtual spatialization channel mixer module
  *               -> gives the feeling of a real room with a simple headphone
  *****************************************************************************
- * Copyright (C) 2002 VideoLAN
- * $Id: headphone.c,v 1.3 2003/02/11 17:20:44 babal Exp $
+ * Copyright (C) 2002-2005 the VideoLAN team
+ * $Id$
  *
  * Authors: Boris Dorès <babal@via.ecp.fr>
  *
@@ -45,8 +45,27 @@ static void DoWork    ( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
 /*****************************************************************************
  * Module descriptor
  *****************************************************************************/
+#define MODULE_DESCRIPTION N_ ( \
+     "This effect gives you the feeling that you are standing in a room " \
+     "with a complete 7.1 speaker set when using only a headphone, " \
+     "providing a more realistic sound experience. It should also be " \
+     "more comfortable and less tiring when listening to music for " \
+     "long periods of time.\nIt works with any source format from mono " \
+     "to 7.1.")
+
+#define HEADPHONE_DIM_TEXT N_("Characteristic dimension")
+#define HEADPHONE_DIM_LONGTEXT N_( \
+     "Distance between front left speaker and listener in meters.")
+
 vlc_module_begin();
-    set_description( _("headphone channel mixer with virtual spatialization effect") );
+    set_description( N_("Headphone channel mixer with virtual spatialization effect") );
+    set_shortname( _("Headphone effect") );
+    set_category( CAT_AUDIO );
+    set_subcategory( SUBCAT_AUDIO_AFILTER );
+
+    add_integer( "headphone-dim", 10, NULL, HEADPHONE_DIM_TEXT,
+                 HEADPHONE_DIM_LONGTEXT, VLC_FALSE );
+
     set_capability( "audio filter", 0 );
     set_callbacks( Create, Destroy );
     add_shortcut( "headphone" );
@@ -165,6 +184,10 @@ static int Init ( aout_filter_t * p_filter , struct aout_filter_sys_t * p_data
 
     /* Number of elementary operations */
     p_data->i_nb_atomic_operations = i_nb_channels * 2;
+    if ( i_physical_channels & AOUT_CHAN_CENTER )
+    {
+        p_data->i_nb_atomic_operations += 2;
+    }
     p_data->p_atomic_operations = malloc ( sizeof(struct atomic_operation_t)
             * p_data->i_nb_atomic_operations );
     if ( p_data->p_atomic_operations == NULL )
@@ -193,59 +216,64 @@ static int Init ( aout_filter_t * p_filter , struct aout_filter_sys_t * p_data
         i_next_atomic_operation += 2;
         i_source_channel_offset++;
     }
-    if ( i_physical_channels & AOUT_CHAN_REARLEFT )
+    if ( i_physical_channels & AOUT_CHAN_MIDDLELEFT )
     {
         ComputeChannelOperations ( p_data , i_rate
                 , i_next_atomic_operation , i_source_channel_offset
-                , -d_x , d_z_rear , 1.5 / i_nb_channels );
+                , -d_x , 0 , 1.5 / i_nb_channels );
         i_next_atomic_operation += 2;
         i_source_channel_offset++;
     }
-    if ( i_physical_channels & AOUT_CHAN_REARRIGHT )
+    if ( i_physical_channels & AOUT_CHAN_MIDDLERIGHT )
     {
         ComputeChannelOperations ( p_data , i_rate
                 , i_next_atomic_operation , i_source_channel_offset
-                , d_x , d_z_rear , 1.5 / i_nb_channels );
+                , d_x , 0 , 1.5 / i_nb_channels );
         i_next_atomic_operation += 2;
         i_source_channel_offset++;
     }
-    if ( i_physical_channels & AOUT_CHAN_REARCENTER )
+    if ( i_physical_channels & AOUT_CHAN_REARLEFT )
     {
         ComputeChannelOperations ( p_data , i_rate
                 , i_next_atomic_operation , i_source_channel_offset
-                , 0 , -d_z , 1.5 / i_nb_channels );
+                , -d_x , d_z_rear , 1.5 / i_nb_channels );
         i_next_atomic_operation += 2;
         i_source_channel_offset++;
     }
-    if ( i_physical_channels & AOUT_CHAN_CENTER )
+    if ( i_physical_channels & AOUT_CHAN_REARRIGHT )
     {
         ComputeChannelOperations ( p_data , i_rate
                 , i_next_atomic_operation , i_source_channel_offset
-                , 0 , d_z , 1.5 / i_nb_channels );
+                , d_x , d_z_rear , 1.5 / i_nb_channels );
         i_next_atomic_operation += 2;
         i_source_channel_offset++;
     }
-    if ( i_physical_channels & AOUT_CHAN_LFE )
+    if ( i_physical_channels & AOUT_CHAN_REARCENTER )
     {
         ComputeChannelOperations ( p_data , i_rate
                 , i_next_atomic_operation , i_source_channel_offset
-                , 0 , d_z_rear , 5.0 / i_nb_channels );
+                , 0 , -d_z , 1.5 / i_nb_channels );
         i_next_atomic_operation += 2;
         i_source_channel_offset++;
     }
-    if ( i_physical_channels & AOUT_CHAN_MIDDLELEFT )
+    if ( i_physical_channels & AOUT_CHAN_CENTER )
     {
+        /* having two center channels increases the spatialization effect */
         ComputeChannelOperations ( p_data , i_rate
                 , i_next_atomic_operation , i_source_channel_offset
-                , -d_x , 0 , 1.5 / i_nb_channels );
+                , d_x / 5.0 , d_z , 0.75 / i_nb_channels );
+        i_next_atomic_operation += 2;
+        ComputeChannelOperations ( p_data , i_rate
+                , i_next_atomic_operation , i_source_channel_offset
+                , -d_x / 5.0 , d_z , 0.75 / i_nb_channels );
         i_next_atomic_operation += 2;
         i_source_channel_offset++;
     }
-    if ( i_physical_channels & AOUT_CHAN_MIDDLERIGHT )
+    if ( i_physical_channels & AOUT_CHAN_LFE )
     {
         ComputeChannelOperations ( p_data , i_rate
                 , i_next_atomic_operation , i_source_channel_offset
-                , d_x , 0 , 1.5 / i_nb_channels );
+                , 0 , d_z_rear , 5.0 / i_nb_channels );
         i_next_atomic_operation += 2;
         i_source_channel_offset++;
     }
@@ -282,22 +310,54 @@ static int Init ( aout_filter_t * p_filter , struct aout_filter_sys_t * p_data
 static int Create( vlc_object_t *p_this )
 {
     aout_filter_t * p_filter = (aout_filter_t *)p_this;
+    vlc_bool_t b_fit = VLC_TRUE;
+
+    /* Activate this filter only with stereo devices */
+    if ( p_filter->output.i_physical_channels != (AOUT_CHAN_LEFT|AOUT_CHAN_RIGHT)
+          || p_filter->output.i_physical_channels
+                != ( p_filter->output.i_original_channels & AOUT_CHAN_PHYSMASK )
+          || p_filter->input.i_physical_channels
+                != ( p_filter->input.i_original_channels & AOUT_CHAN_PHYSMASK ) )
+    {
+        msg_Dbg( p_filter, "Filter discarded (incompatible format)" );
+        return VLC_EGENERIC;
+    }
 
-    if ( p_filter->output.i_physical_channels != ( AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT )
-          || p_filter->input.i_format != p_filter->output.i_format
-          || p_filter->input.i_rate != p_filter->output.i_rate
-          || (p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
-               && p_filter->input.i_format != VLC_FOURCC('f','i','3','2')) )
+    /* Request a specific format if not already compatible */
+    if ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2')
+          || p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
     {
-        return -1;
+        b_fit = VLC_FALSE;
+        p_filter->input.i_format = VLC_FOURCC('f','l','3','2');
+        p_filter->output.i_format = VLC_FOURCC('f','l','3','2');
+    }
+    if ( p_filter->input.i_rate != p_filter->output.i_rate )
+    {
+        b_fit = VLC_FALSE;
+        p_filter->input.i_rate = p_filter->output.i_rate;
+    }
+    if ( p_filter->input.i_physical_channels == (AOUT_CHAN_LEFT|AOUT_CHAN_RIGHT)
+          && ( p_filter->input.i_original_channels & AOUT_CHAN_DOLBYSTEREO ) )
+    {
+        b_fit = VLC_FALSE;
+        p_filter->input.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
+                                              AOUT_CHAN_CENTER |
+                                              AOUT_CHAN_REARLEFT |
+                                              AOUT_CHAN_REARRIGHT;
+        p_filter->input.i_original_channels = p_filter->input.i_physical_channels;
+    }
+    if ( ! b_fit )
+    {
+        msg_Dbg( p_filter, "Requesting specific format" );
+        return VLC_EGENERIC;
     }
 
     /* Allocate the memory needed to store the module's structure */
     p_filter->p_sys = malloc( sizeof(struct aout_filter_sys_t) );
     if ( p_filter->p_sys == NULL )
     {
-        msg_Err( p_filter, "out of memory" );
-        return -1;
+        msg_Err( p_filter, "Out of memory" );
+        return VLC_EGENERIC;
     }
     p_filter->p_sys->i_overflow_buffer_size = 0;
     p_filter->p_sys->p_overflow_buffer = NULL;
@@ -309,13 +369,13 @@ static int Create( vlc_object_t *p_this )
                 , p_filter->input.i_physical_channels
                 ,  p_filter->input.i_rate ) < 0 )
     {
-        return -1;
+        return VLC_EGENERIC;
     }
 
     p_filter->pf_do_work = DoWork;
     p_filter->b_in_place = 0;
 
-    return 0;
+    return VLC_SUCCESS;
 }
 
 /*****************************************************************************