]> git.sesse.net Git - vlc/commitdiff
- new headphone channel mixer with virtual spatialization effect : This
authorBoris Dorès <babal@videolan.org>
Mon, 9 Dec 2002 00:52:42 +0000 (00:52 +0000)
committerBoris Dorès <babal@videolan.org>
Mon, 9 Dec 2002 00:52:42 +0000 (00:52 +0000)
  effect should give you the feeling that you stands in a real room with
  a complete 5.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.It
  works with any source format from mono to 5.1.

  -> please try it and feel free to give me some feedback. Some
     improvements are already planned (adding echo, more configuration
     options, ...).

NB: whereas the filter itself is in a (very first) stable version, the
    way it is integrated to the filter chain is only a _temporary_ hack
    since it's the audio ouput core (input.c actually) which is directly
    responsible for it. Integrating it in a more suitable way will
    probably require some work on the way the filters are selected as
    well as on the configuration level, but I'm working on it :)

AUTHORS
ChangeLog
configure.ac.in
modules/LIST
modules/audio_filter/channel_mixer/Modules.am
modules/audio_filter/channel_mixer/headphone.c [new file with mode: 0644]
src/audio_output/input.c
src/libvlc.h

diff --git a/AUTHORS b/AUTHORS
index f4372fb772bf957b53848d312dde1d0f1834bce4..10ab6e5189e6ed912bfba7610750b74d7919b205 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -129,6 +129,7 @@ E: babal@via.ecp.fr
 C: babal
 D: Win32 network input
 D: Win32 interface
+D: Headphone channel mixer
 S: France
 
 N: Jean-Marc Dressler
index de8a4269002377ed7807d1ca1c157e5ae2129f8a..1e0c0dd7bbc3a8b158f9a1914d32bb39e1119fcd 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,9 @@
 0.5.0
 Not released yet
 
+  * ./modules/audio_filter/channel_mixer/headphone.x: new headphone channel
+    mixer with virtual spatialization effect
+  * ./modules/gui/win32/preferences.*: redesigned preference dialog box
   * ./modules/audio_filter/resampler/linear.c: new audio resampler based on
     linear interpolation
   * ./modules/gui/macosx/prefs.m: new configuration interface
index 78c8cd8661d81ea590c49457d07833ef6829733e..31b75ff246518a58495e621cbd02edd4fe0d4c59 100644 (file)
@@ -688,7 +688,7 @@ PLUGINS="${PLUGINS} lpcm a52"
 PLUGINS="${PLUGINS} deinterlace invert adjust wall transform distort clone crop motionblur"
 PLUGINS="${PLUGINS} float32tos16 float32tos8 float32tou16 float32tou8 a52tospdif fixed32tofloat32 fixed32tos16 s16tofloat32 s16tofloat32swab s8tofloat32 u8tofixed32 u8tofloat32"
 PLUGINS="${PLUGINS} trivial_resampler ugly_resampler linear_resampler"
-PLUGINS="${PLUGINS} trivial_channel_mixer"
+PLUGINS="${PLUGINS} trivial_channel_mixer headphone_channel_mixer"
 PLUGINS="${PLUGINS} trivial_mixer spdif_mixer float32_mixer"
 PLUGINS="${PLUGINS} aout_file"
 #PLUGINS="${PLUGINS} scope"
index a9fe90d1fbd91410f6316db13b84e18c72c82671..3224aff6db218ed324ea41ea5b1ca9b694c8f94e 100644 (file)
@@ -1,5 +1,5 @@
 List of vlc plugins
-$Id: LIST,v 1.5 2002/11/21 21:37:46 gbazin Exp $
+$Id: LIST,v 1.6 2002/12/09 00:52:42 babal Exp $
 
  * a52_system: input module for A52 decapsulation.
 
@@ -66,6 +66,8 @@ $Id: LIST,v 1.5 2002/11/21 21:37:46 gbazin Exp $
 
  * gtk: interface using the Gtk+ widget set.
 
+ * headphone: headphone channel mixer with virtual spatialization effect.
+
  * idct: inverse DCT module, used by the video decoder.
 
  * idctclassic: another version of idct.
index fc0f05b224c41b66667e948400e79b75a4c17870..b68c7cda70aa021d6e6c0cdf6fe8bff66494b122 100644 (file)
@@ -1 +1,2 @@
 SOURCES_trivial_channel_mixer = modules/audio_filter/channel_mixer/trivial.c
+SOURCES_headphone_channel_mixer = modules/audio_filter/channel_mixer/headphone.c
diff --git a/modules/audio_filter/channel_mixer/headphone.c b/modules/audio_filter/channel_mixer/headphone.c
new file mode 100644 (file)
index 0000000..ee7c3a4
--- /dev/null
@@ -0,0 +1,429 @@
+/*****************************************************************************
+ * 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.1 2002/12/09 00:52:42 babal Exp $
+ *
+ * Authors: Boris Dorès <babal@via.ecp.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include <stdlib.h>                                      /* malloc(), free() */
+#include <string.h>
+#include <math.h>                                        /* sqrt */
+
+#include <vlc/vlc.h>
+#include "audio_output.h"
+#include "aout_internal.h"
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+static int  Create    ( vlc_object_t * );
+static void Destroy   ( vlc_object_t * );
+
+static void DoWork    ( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
+                        aout_buffer_t * );
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+vlc_module_begin();
+    set_description( _("headphone channel mixer with virtual spatialization effect") );
+    set_capability( "audio filter", 0 );
+    set_callbacks( Create, Destroy );
+    add_shortcut( "headphone" );
+vlc_module_end();
+
+
+/*****************************************************************************
+ * Internal data structures
+ *****************************************************************************/
+struct atomic_operation_t
+{
+    int i_source_channel_offset;
+    int i_dest_channel_offset;
+    unsigned int i_delay;/* in sample unit */
+    double d_amplitude_factor;
+};
+
+struct aout_filter_sys_t
+{
+    size_t i_overflow_buffer_size;/* in bytes */
+    byte_t * p_overflow_buffer;
+    unsigned int i_nb_atomic_operations;
+    struct atomic_operation_t * p_atomic_operations;
+};
+
+/*****************************************************************************
+ * Init: initialize internal data structures
+ * and computes the needed atomic operations
+ *****************************************************************************/
+/* x and z represent the coordinates of the virtual speaker
+ *  relatively to the center of the listener's head, measured in meters :
+ *
+ *  left              right
+ *Z
+ *-
+ *a          head
+ *x
+ *i
+ *s
+ *  rear left    rear right
+ *
+ *          x-axis
+ *  */
+static void ComputeChannelOperations ( struct aout_filter_sys_t * p_data
+        , unsigned int i_rate , unsigned int i_next_atomic_operation
+        , int i_source_channel_offset , double d_x , double d_z
+        , double d_channel_amplitude_factor )
+{
+    double d_c = 340; /*sound celerity (unit: m/s)*/
+
+    /* Left ear */
+    p_data->p_atomic_operations[i_next_atomic_operation]
+        .i_source_channel_offset = i_source_channel_offset;
+    p_data->p_atomic_operations[i_next_atomic_operation]
+        .i_dest_channel_offset = 0;/* left */
+    p_data->p_atomic_operations[i_next_atomic_operation]
+        .i_delay = (int)( sqrt( (-0.1-d_x)*(-0.1-d_x) + (0-d_z)*(0-d_z) )
+                          / d_c * i_rate );
+    if ( d_x < 0 )
+    {
+        p_data->p_atomic_operations[i_next_atomic_operation]
+            .d_amplitude_factor = d_channel_amplitude_factor * 1.1 / 2;
+    }
+    else if ( d_x > 0 )
+    {
+        p_data->p_atomic_operations[i_next_atomic_operation]
+            .d_amplitude_factor = d_channel_amplitude_factor * 0.9 / 2;
+    }
+    else
+    {
+        p_data->p_atomic_operations[i_next_atomic_operation]
+            .d_amplitude_factor = d_channel_amplitude_factor / 2;
+    }
+
+    /* Right ear */
+    p_data->p_atomic_operations[i_next_atomic_operation + 1]
+        .i_source_channel_offset = i_source_channel_offset;
+    p_data->p_atomic_operations[i_next_atomic_operation + 1]
+        .i_dest_channel_offset = 1;/* right */
+    p_data->p_atomic_operations[i_next_atomic_operation + 1]
+        .i_delay = (int)( sqrt( (0.1-d_x)*(0.1-d_x) + (0-d_z)*(0-d_z) )
+                          / d_c * i_rate );
+    if ( d_x < 0 )
+    {
+        p_data->p_atomic_operations[i_next_atomic_operation + 1]
+            .d_amplitude_factor = d_channel_amplitude_factor * 0.9 / 2;
+    }
+    else if ( d_x > 0 )
+    {
+        p_data->p_atomic_operations[i_next_atomic_operation + 1]
+            .d_amplitude_factor = d_channel_amplitude_factor * 1.1 / 2;
+    }
+    else
+    {
+        p_data->p_atomic_operations[i_next_atomic_operation + 1]
+            .d_amplitude_factor = d_channel_amplitude_factor / 2;
+    }
+}
+
+static int Init ( aout_filter_t * p_filter , struct aout_filter_sys_t * p_data
+        , unsigned int i_nb_channels , uint32_t i_physical_channels
+        , unsigned int i_rate )
+{
+    double d_x = config_GetInt ( p_filter , "headphone-dim" );
+    double d_z = d_x;
+    double d_z_rear = -d_x/3;
+    unsigned int i_next_atomic_operation;
+    int i_source_channel_offset;
+    unsigned int i;
+
+    if ( p_data == NULL )
+    {
+        msg_Dbg ( p_filter, "passing a null pointer as argument" );
+        return 0;
+    }
+
+    /* Number of elementary operations */
+    p_data->i_nb_atomic_operations = i_nb_channels * 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 )
+    {
+        msg_Err( p_filter, "out of memory" );
+        return -1;
+    }
+
+    /* For each virtual speaker, computes elementary wave propagation time
+     * to each ear */
+    i_next_atomic_operation = 0;
+    i_source_channel_offset = 0;
+    if ( i_physical_channels & AOUT_CHAN_LEFT )
+    {
+        ComputeChannelOperations ( p_data , i_rate
+                , i_next_atomic_operation , i_source_channel_offset
+                , -d_x , d_z , 2.0 / i_nb_channels );
+        i_next_atomic_operation += 2;
+        i_source_channel_offset++;
+    }
+    if ( i_physical_channels & AOUT_CHAN_RIGHT )
+    {
+        ComputeChannelOperations ( p_data , i_rate
+                , i_next_atomic_operation , i_source_channel_offset
+                , d_x , d_z , 2.0 / i_nb_channels );
+        i_next_atomic_operation += 2;
+        i_source_channel_offset++;
+    }
+    if ( i_physical_channels & AOUT_CHAN_REARLEFT )
+    {
+        ComputeChannelOperations ( p_data , i_rate
+                , i_next_atomic_operation , i_source_channel_offset
+                , -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_REARRIGHT )
+    {
+        ComputeChannelOperations ( p_data , i_rate
+                , i_next_atomic_operation , i_source_channel_offset
+                , 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 )
+    {
+        ComputeChannelOperations ( p_data , i_rate
+                , i_next_atomic_operation , i_source_channel_offset
+                , 0 , d_z , 1.5 / i_nb_channels );
+        i_next_atomic_operation += 2;
+        i_source_channel_offset++;
+    }
+    if ( i_physical_channels & AOUT_CHAN_LFE )
+    {
+        ComputeChannelOperations ( p_data , i_rate
+                , i_next_atomic_operation , i_source_channel_offset
+                , 0 , d_z_rear , 5.0 / i_nb_channels );
+        i_next_atomic_operation += 2;
+        i_source_channel_offset++;
+    }
+
+    /* Initialize the overflow buffer
+     * we need it because the process induce a delay in the samples */
+    p_data->i_overflow_buffer_size = 0;
+    for ( i = 0 ; i < p_data->i_nb_atomic_operations ; i++ )
+    {
+        if ( p_data->i_overflow_buffer_size
+                < p_data->p_atomic_operations[i].i_delay * i_nb_channels
+                * sizeof (float) )
+        {
+            p_data->i_overflow_buffer_size
+                = p_data->p_atomic_operations[i].i_delay * i_nb_channels
+                * sizeof (float);
+        }
+    }
+    p_data->p_overflow_buffer = malloc ( p_data->i_overflow_buffer_size );
+    if ( p_data->p_atomic_operations == NULL )
+    {
+        msg_Err( p_filter, "out of memory" );
+        return -1;
+    }
+    memset ( p_data->p_overflow_buffer , 0 , p_data->i_overflow_buffer_size );
+
+    /* end */
+    return 0;
+}
+
+/*****************************************************************************
+ * Create: allocate headphone downmixer
+ *****************************************************************************/
+static int Create( vlc_object_t *p_this )
+{
+    aout_filter_t * p_filter = (aout_filter_t *)p_this;
+
+    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')) )
+    {
+        return -1;
+    }
+
+    /* 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;
+    }
+    p_filter->p_sys->i_overflow_buffer_size = 0;
+    p_filter->p_sys->p_overflow_buffer = NULL;
+    p_filter->p_sys->i_nb_atomic_operations = 0;
+    p_filter->p_sys->p_atomic_operations = NULL;
+
+    if ( Init( p_filter , p_filter->p_sys
+                , aout_FormatNbChannels ( &p_filter->input )
+                , p_filter->input.i_physical_channels
+                ,  p_filter->input.i_rate ) < 0 )
+    {
+        return -1;
+    }
+
+    p_filter->pf_do_work = DoWork;
+    p_filter->b_in_place = 0;
+
+    return 0;
+}
+
+/*****************************************************************************
+ * Destroy: deallocate resources associated with headphone downmixer
+ *****************************************************************************/
+static void Destroy( vlc_object_t *p_this )
+{
+    aout_filter_t * p_filter = (aout_filter_t *)p_this;
+
+    if ( p_filter->p_sys != NULL )
+    {
+        if ( p_filter->p_sys->p_overflow_buffer != NULL )
+        {
+            free ( p_filter->p_sys->p_overflow_buffer );
+        }
+        if ( p_filter->p_sys->p_atomic_operations != NULL )
+        {
+            free ( p_filter->p_sys->p_atomic_operations );
+        }
+        free ( p_filter->p_sys );
+        p_filter->p_sys = NULL;
+    }
+}
+
+/*****************************************************************************
+ * DoWork: convert a buffer
+ *****************************************************************************/
+static void DoWork( aout_instance_t * p_aout, aout_filter_t * p_filter,
+                    aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
+{
+    int i_input_nb = aout_FormatNbChannels( &p_filter->input );
+    int i_output_nb = aout_FormatNbChannels( &p_filter->output );
+
+    float * p_in = (float*) p_in_buf->p_buffer;
+    byte_t * p_out;
+    byte_t * p_overflow;
+    byte_t * p_slide;
+
+    size_t i_overflow_size;/* in bytes */
+    size_t i_out_size;/* in bytes */
+
+    unsigned int i, j;
+
+    int i_source_channel_offset;
+    int i_dest_channel_offset;
+    unsigned int i_delay;
+    double d_amplitude_factor;
+
+
+    /* out buffer characterisitcs */
+    p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
+    p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * i_output_nb / i_input_nb;
+    p_out = p_out_buf->p_buffer;
+    i_out_size = p_out_buf->i_nb_bytes;
+
+    if ( p_filter->p_sys != NULL )
+    {
+        /* Slide the overflow buffer */
+        p_overflow = p_filter->p_sys->p_overflow_buffer;
+        i_overflow_size = p_filter->p_sys->i_overflow_buffer_size;
+
+        memset ( p_out , 0 , i_out_size );
+        if ( i_out_size > i_overflow_size )
+            memcpy ( p_out , p_overflow , i_overflow_size );
+        else
+            memcpy ( p_out , p_overflow , i_out_size );
+
+        p_slide = p_filter->p_sys->p_overflow_buffer;
+        while ( p_slide < p_overflow + i_overflow_size )
+        {
+            if ( p_slide + i_out_size < p_overflow + i_overflow_size )
+            {
+                memset ( p_slide , 0 , i_out_size );
+                if ( p_slide + 2 * i_out_size < p_overflow + i_overflow_size )
+                    memcpy ( p_slide , p_slide + i_out_size , i_out_size );
+                else
+                    memcpy ( p_slide , p_slide + i_out_size
+                      , p_overflow + i_overflow_size - ( p_slide + i_out_size ) );
+            }
+            else
+            {
+                memset ( p_slide , 0 , p_overflow + i_overflow_size - p_slide );
+            }
+            p_slide += i_out_size;
+        }
+
+        /* apply the atomic operations */
+        for ( i = 0 ; i < p_filter->p_sys->i_nb_atomic_operations ; i++ )
+        {
+            /* shorter variable names */
+            i_source_channel_offset
+                = p_filter->p_sys->p_atomic_operations[i].i_source_channel_offset;
+            i_dest_channel_offset
+                = p_filter->p_sys->p_atomic_operations[i].i_dest_channel_offset;
+            i_delay = p_filter->p_sys->p_atomic_operations[i].i_delay;
+            d_amplitude_factor
+                = p_filter->p_sys->p_atomic_operations[i].d_amplitude_factor;
+
+            if ( p_out_buf->i_nb_samples > i_delay )
+            {
+                /* current buffer coefficients */
+                for ( j = 0 ; j < p_out_buf->i_nb_samples - i_delay ; j++ )
+                {
+                    ((float*)p_out)[ (i_delay+j)*i_output_nb + i_dest_channel_offset ]
+                        += p_in[ j * i_input_nb + i_source_channel_offset ]
+                           * d_amplitude_factor;
+                }
+
+                /* overflow buffer coefficients */
+                for ( j = 0 ; j < i_delay ; j++ )
+                {
+                    ((float*)p_overflow)[ j*i_output_nb + i_dest_channel_offset ]
+                        += p_in[ (p_out_buf->i_nb_samples - i_delay + j)
+                           * i_input_nb + i_source_channel_offset ]
+                           * d_amplitude_factor;
+                }
+            }
+            else
+            {
+                /* overflow buffer coefficients only */
+                for ( j = 0 ; j < p_out_buf->i_nb_samples ; j++ )
+                {
+                    ((float*)p_overflow)[ (i_delay - p_out_buf->i_nb_samples + j)
+                        * i_output_nb + i_dest_channel_offset ]
+                        += p_in[ j * i_input_nb + i_source_channel_offset ]
+                           * d_amplitude_factor;
+                }
+            }
+        }
+    }
+    else
+    {
+        memset ( p_out , 0 , i_out_size );
+    }
+}
index c44266ccf92714ef28af973189d029469530dfb1..40204f2e71d08a12e9ea95704e9daed7bcb5e0a1 100644 (file)
@@ -2,7 +2,7 @@
  * input.c : internal management of input streams for the audio output
  *****************************************************************************
  * Copyright (C) 2002 VideoLAN
- * $Id: input.c,v 1.26 2002/12/06 10:10:39 sam Exp $
+ * $Id: input.c,v 1.27 2002/12/09 00:52:42 babal Exp $
  *
  * Authors: Christophe Massiot <massiot@via.ecp.fr>
  *
@@ -41,7 +41,8 @@
  *****************************************************************************/
 int aout_InputNew( aout_instance_t * p_aout, aout_input_t * p_input )
 {
-    audio_sample_format_t intermediate_format;
+    audio_sample_format_t intermediate_format, headphone_intermediate_format;
+    aout_filter_t * p_headphone_filter;
 
     aout_FormatPrint( p_aout, "input", &p_input->input );
 
@@ -52,10 +53,23 @@ int aout_InputNew( aout_instance_t * p_aout, aout_input_t * p_input )
     /* Create filters. */
     memcpy( &intermediate_format, &p_aout->mixer.mixer,
             sizeof(audio_sample_format_t) );
+    memcpy( &headphone_intermediate_format, &p_aout->mixer.mixer,
+            sizeof(audio_sample_format_t) );
+    if ( config_GetInt( p_aout , "headphone" ) )
+    {
+        headphone_intermediate_format.i_physical_channels = p_input->input.i_physical_channels;
+        headphone_intermediate_format.i_original_channels = p_input->input.i_original_channels;
+        headphone_intermediate_format.i_bytes_per_frame =
+                headphone_intermediate_format.i_bytes_per_frame
+                * aout_FormatNbChannels( &headphone_intermediate_format )
+                / aout_FormatNbChannels( &intermediate_format );
+    }
+
     intermediate_format.i_rate = p_input->input.i_rate;
+    headphone_intermediate_format.i_rate = p_input->input.i_rate;
     if ( aout_FiltersCreatePipeline( p_aout, p_input->pp_filters,
                                      &p_input->i_nb_filters, &p_input->input,
-                                     &intermediate_format ) < 0 )
+                                     &headphone_intermediate_format ) < 0 )
     {
         msg_Err( p_aout, "couldn't set an input pipeline" );
 
@@ -65,6 +79,43 @@ int aout_InputNew( aout_instance_t * p_aout, aout_input_t * p_input )
         return -1;
     }
 
+    if ( config_GetInt( p_aout , "headphone" ) )
+    {
+        /* create a vlc object */
+        p_headphone_filter = vlc_object_create( p_aout
+                , sizeof(aout_filter_t) );
+        if ( p_headphone_filter == NULL )
+        {
+            msg_Err( p_aout, "couldn't open the headphone virtual spatialization module" );
+            aout_FifoDestroy( p_aout, &p_input->fifo );
+            p_input->b_error = 1;
+            return -1;
+        }
+        vlc_object_attach( p_headphone_filter, p_aout );
+
+        /* find the headphone filter */
+        memcpy( &p_headphone_filter->input, &headphone_intermediate_format
+                , sizeof(audio_sample_format_t) );
+        memcpy( &p_headphone_filter->output, &intermediate_format
+                , sizeof(audio_sample_format_t) );
+        p_headphone_filter->p_module = module_Need( p_headphone_filter, "audio filter"
+                , "headphone" );
+        if ( p_headphone_filter->p_module == NULL )
+        {
+            vlc_object_detach( p_headphone_filter );
+            vlc_object_destroy( p_headphone_filter );
+
+            msg_Err( p_aout, "couldn't open the headphone virtual spatialization module" );
+            aout_FifoDestroy( p_aout, &p_input->fifo );
+            p_input->b_error = 1;
+            return -1;
+        }
+
+        /* success */
+        p_headphone_filter->b_reinit = VLC_TRUE;
+        p_input->pp_filters[p_input->i_nb_filters++] = p_headphone_filter;
+    }
+
     /* Prepare hints for the buffer allocator. */
     p_input->input_alloc.i_alloc_type = AOUT_ALLOC_HEAP;
     p_input->input_alloc.i_bytes_per_sec = -1;
index 57c807a695a187a71f614d329c1cf9401b775cc2..b0e05a9f53c18899a42b163eee6716d732d07c0b 100644 (file)
@@ -2,7 +2,7 @@
  * libvlc.h: main libvlc header
  *****************************************************************************
  * Copyright (C) 1998-2002 VideoLAN
- * $Id: libvlc.h,v 1.27 2002/12/07 22:29:15 titer Exp $
+ * $Id: libvlc.h,v 1.28 2002/12/09 00:52:42 babal Exp $
  *
  * Authors: Vincent Seguin <seguin@via.ecp.fr>
  *          Samuel Hocevar <sam@zoy.org>
     "This option allows you to delay the audio output. This can be handy if " \
     "you notice a lag between the video and the audio.")
 
+#define HEADPHONE_TEXT N_("headphone virtual spatialization effect")
+#define HEADPHONE_LONGTEXT N_( \
+    "This effect gives you the feeling that you stands in a real room " \
+    "with a complete 5.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 5.1.")
+
+#define HEADPHONE_DIM_TEXT N_("characteristic dimension")
+#define HEADPHONE_DIM_LONGTEXT N_( \
+     "Headphone virtual spatialization effect parameter: "\
+     "distance between front left speaker and listener in meters.")
+
 #define VOUT_TEXT N_("video output module")
 #define VOUT_LONGTEXT N_( \
     "This option allows you to select the video output method used by vlc. " \
@@ -400,6 +414,9 @@ vlc_module_begin();
                  AOUT_CHANNELS_TEXT, AOUT_CHANNELS_LONGTEXT );
     add_integer( "desync", 0, NULL, DESYNC_TEXT, DESYNC_LONGTEXT );
     add_integer( "audio-format", 0, NULL, FORMAT_TEXT, FORMAT_LONGTEXT );
+    add_bool( "headphone", 0, NULL, HEADPHONE_TEXT, HEADPHONE_LONGTEXT );
+    add_integer( "headphone-dim", 5, NULL, HEADPHONE_DIM_TEXT,
+                 HEADPHONE_DIM_LONGTEXT );
 
     /* Video options */
     add_category_hint( N_("Video"), NULL );