Changeset 1d0b15b5cb9fae31bdc56931a0167556cc4ebe92

Show
Ignore:
Timestamp:
08/29/06 11:49:07 (2 years ago)
Author:
Jean-Paul Saman <jpsaman@videolan.org>
git-committer:
Jean-Paul Saman <jpsaman@videolan.org> 1156844947 +0000
git-parent:

[1e85ac0bb43423e5f5f63c111842ff6a5c371034]

git-author:
Jean-Paul Saman <jpsaman@videolan.org> 1156844947 +0000
Message:

Resample audio channels when doing real stereo to mono.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • modules/audio_filter/converter/mono.c

    rbf490f9 r1d0b15b  
    2727#include <stdlib.h>                                      /* malloc(), free() */ 
    2828#include <string.h> 
     29#include <math.h>                                        /* sqrt */ 
    2930 
    3031#ifdef HAVE_STDINT_H 
     
    5556static unsigned int stereo_to_mono( aout_instance_t *, aout_filter_t *, 
    5657                                    aout_buffer_t *, aout_buffer_t * ); 
     58static void stereo2mono_downmix( aout_instance_t *, aout_filter_t *, 
     59                                 aout_buffer_t *, aout_buffer_t * ); 
    5760 
    5861/***************************************************************************** 
    5962 * Local structures 
    6063 *****************************************************************************/ 
     64struct atomic_operation_t 
     65{ 
     66    int i_source_channel_offset; 
     67    int i_dest_channel_offset; 
     68    unsigned int i_delay;/* in sample unit */ 
     69    double d_amplitude_factor; 
     70}; 
     71 
    6172struct filter_sys_t 
    6273{ 
    63     int i_nb_channels; /* number of float32 per sample */ 
     74    vlc_bool_t b_downmix; 
     75 
     76    int i_nb_channels; /* number of int16_t per sample */ 
    6477    int i_channel_selected; 
    6578    int i_bitspersample; 
     79 
     80    size_t i_overflow_buffer_size;/* in bytes */ 
     81    byte_t * p_overflow_buffer; 
     82    unsigned int i_nb_atomic_operations; 
     83    struct atomic_operation_t * p_atomic_operations; 
    6684}; 
    6785 
     86#define MONO_DOWNMIX_TEXT ("Use downmix algorithme.") 
     87#define MONO_DOWNMIX_LONGTEXT ("This option selects a stereo to mono " \ 
     88    "downmix algorithm that is used in the headphone channel mixer. It" \ 
     89    "gives the effect of standing in a room full of speakers." ) 
     90 
    6891#define MONO_CHANNEL_TEXT ("Select channel to keep") 
    69 #define MONO_CHANNEL_LONGTEXT ("This option silcences all other channels " \ 
     92#define MONO_CHANNEL_LONGTEXT ("This option silences all other channels " \ 
    7093    "except the selected channel. Choose one from (0=left, 1=right " \ 
    7194    "2=rear left, 3=rear right, 4=center, 5=left front)") 
     
    89112    set_capability( "audio filter2", 5 ); 
    90113 
    91     add_integer( MONO_CFG "mono-channel", -1, NULL, MONO_CHANNEL_TEXT, MONO_CHANNEL_LONGTEXT, VLC_FALSE ); 
     114    add_bool( MONO_CFG "mono-downmix", VLC_FALSE, NULL, MONO_DOWNMIX_TEXT, 
     115              MONO_DOWNMIX_LONGTEXT, VLC_FALSE ); 
     116    add_integer( MONO_CFG "mono-channel", -1, NULL, MONO_CHANNEL_TEXT, 
     117        MONO_CHANNEL_LONGTEXT, VLC_FALSE ); 
    92118        change_integer_list( pi_pos_values, ppsz_pos_descriptions, 0 ); 
    93119 
     
    98124vlc_module_end(); 
    99125 
     126/* Init() and ComputeChannelOperations() - 
     127 * Code taken from modules/audio_filter/channel_mixer/headphone.c 
     128 * converted from float into int16_t based downmix 
     129 * Written by Boris Dorès <babal@via.ecp.fr> 
     130 */ 
     131 
     132/***************************************************************************** 
     133 * Init: initialize internal data structures 
     134 * and computes the needed atomic operations 
     135 *****************************************************************************/ 
     136/* x and z represent the coordinates of the virtual speaker 
     137 *  relatively to the center of the listener's head, measured in meters : 
     138 * 
     139 *  left              right 
     140 *Z 
     141 *- 
     142 *a          head 
     143 *x 
     144 *i 
     145 *s 
     146 *  rear left    rear right 
     147 * 
     148 *          x-axis 
     149 *  */ 
     150static void ComputeChannelOperations( struct filter_sys_t * p_data, 
     151        unsigned int i_rate, unsigned int i_next_atomic_operation, 
     152        int i_source_channel_offset, double d_x, double d_z, 
     153        double d_compensation_length, double d_channel_amplitude_factor ) 
     154{ 
     155    double d_c = 340; /*sound celerity (unit: m/s)*/ 
     156    double d_compensation_delay = (d_compensation_length-0.1) / d_c * i_rate; 
     157 
     158    /* Left ear */ 
     159    p_data->p_atomic_operations[i_next_atomic_operation] 
     160        .i_source_channel_offset = i_source_channel_offset; 
     161    p_data->p_atomic_operations[i_next_atomic_operation] 
     162        .i_dest_channel_offset = 0;/* left */ 
     163    p_data->p_atomic_operations[i_next_atomic_operation] 
     164        .i_delay = (int)( sqrt( (-0.1-d_x)*(-0.1-d_x) + (0-d_z)*(0-d_z) ) 
     165                          / d_c * i_rate - d_compensation_delay ); 
     166    if( d_x < 0 ) 
     167    { 
     168        p_data->p_atomic_operations[i_next_atomic_operation] 
     169            .d_amplitude_factor = d_channel_amplitude_factor * 1.1 / 2; 
     170    } 
     171    else if( d_x > 0 ) 
     172    { 
     173        p_data->p_atomic_operations[i_next_atomic_operation] 
     174            .d_amplitude_factor = d_channel_amplitude_factor * 0.9 / 2; 
     175    } 
     176    else 
     177    { 
     178        p_data->p_atomic_operations[i_next_atomic_operation] 
     179            .d_amplitude_factor = d_channel_amplitude_factor / 2; 
     180    } 
     181 
     182    /* Right ear */ 
     183    p_data->p_atomic_operations[i_next_atomic_operation + 1] 
     184        .i_source_channel_offset = i_source_channel_offset; 
     185    p_data->p_atomic_operations[i_next_atomic_operation + 1] 
     186        .i_dest_channel_offset = 1;/* right */ 
     187    p_data->p_atomic_operations[i_next_atomic_operation + 1] 
     188        .i_delay = (int)( sqrt( (0.1-d_x)*(0.1-d_x) + (0-d_z)*(0-d_z) ) 
     189                          / d_c * i_rate - d_compensation_delay ); 
     190    if( d_x < 0 ) 
     191    { 
     192        p_data->p_atomic_operations[i_next_atomic_operation + 1] 
     193            .d_amplitude_factor = d_channel_amplitude_factor * 0.9 / 2; 
     194    } 
     195    else if( d_x > 0 ) 
     196    { 
     197        p_data->p_atomic_operations[i_next_atomic_operation + 1] 
     198            .d_amplitude_factor = d_channel_amplitude_factor * 1.1 / 2; 
     199    } 
     200    else 
     201    { 
     202        p_data->p_atomic_operations[i_next_atomic_operation + 1] 
     203            .d_amplitude_factor = d_channel_amplitude_factor / 2; 
     204    } 
     205} 
     206 
     207static int Init( vlc_object_t *p_this, struct filter_sys_t * p_data, 
     208                 unsigned int i_nb_channels, uint32_t i_physical_channels, 
     209                 unsigned int i_rate ) 
     210{ 
     211    double d_x = config_GetInt( p_this, "headphone-dim" ); 
     212    double d_z = d_x; 
     213    double d_z_rear = -d_x/3; 
     214    double d_min = 0; 
     215    unsigned int i_next_atomic_operation; 
     216    int i_source_channel_offset; 
     217    unsigned int i; 
     218 
     219    if( p_data == NULL ) 
     220    { 
     221        msg_Dbg( p_this, "passing a null pointer as argument" ); 
     222        return 0; 
     223    } 
     224 
     225    if( config_GetInt( p_this, "headphone-compensate" ) ) 
     226    { 
     227        /* minimal distance to any speaker */ 
     228        if( i_physical_channels & AOUT_CHAN_REARCENTER ) 
     229        { 
     230            d_min = d_z_rear; 
     231        } 
     232        else 
     233        { 
     234            d_min = d_z; 
     235        } 
     236    } 
     237 
     238    /* Number of elementary operations */ 
     239    p_data->i_nb_atomic_operations = i_nb_channels * 2; 
     240    if( i_physical_channels & AOUT_CHAN_CENTER ) 
     241    { 
     242        p_data->i_nb_atomic_operations += 2; 
     243    } 
     244    p_data->p_atomic_operations = malloc( sizeof(struct atomic_operation_t) 
     245            * p_data->i_nb_atomic_operations ); 
     246    if( p_data->p_atomic_operations == NULL ) 
     247    { 
     248        msg_Err( p_this, "out of memory" ); 
     249        return -1; 
     250    } 
     251 
     252    /* For each virtual speaker, computes elementary wave propagation time 
     253     * to each ear */ 
     254    i_next_atomic_operation = 0; 
     255    i_source_channel_offset = 0; 
     256    if( i_physical_channels & AOUT_CHAN_LEFT ) 
     257    { 
     258        ComputeChannelOperations( p_data , i_rate 
     259                , i_next_atomic_operation , i_source_channel_offset 
     260                , -d_x , d_z , d_min , 2.0 / i_nb_channels ); 
     261        i_next_atomic_operation += 2; 
     262        i_source_channel_offset++; 
     263    } 
     264    if( i_physical_channels & AOUT_CHAN_RIGHT ) 
     265    { 
     266        ComputeChannelOperations( p_data , i_rate 
     267                , i_next_atomic_operation , i_source_channel_offset 
     268                , d_x , d_z , d_min , 2.0 / i_nb_channels ); 
     269        i_next_atomic_operation += 2; 
     270        i_source_channel_offset++; 
     271    } 
     272    if( i_physical_channels & AOUT_CHAN_MIDDLELEFT ) 
     273    { 
     274        ComputeChannelOperations( p_data , i_rate 
     275                , i_next_atomic_operation , i_source_channel_offset 
     276                , -d_x , 0 , d_min , 1.5 / i_nb_channels ); 
     277        i_next_atomic_operation += 2; 
     278        i_source_channel_offset++; 
     279    } 
     280    if( i_physical_channels & AOUT_CHAN_MIDDLERIGHT ) 
     281    { 
     282        ComputeChannelOperations( p_data , i_rate 
     283                , i_next_atomic_operation , i_source_channel_offset 
     284                , d_x , 0 , d_min , 1.5 / i_nb_channels ); 
     285        i_next_atomic_operation += 2; 
     286        i_source_channel_offset++; 
     287    } 
     288    if( i_physical_channels & AOUT_CHAN_REARLEFT ) 
     289    { 
     290        ComputeChannelOperations( p_data , i_rate 
     291                , i_next_atomic_operation , i_source_channel_offset 
     292                , -d_x , d_z_rear , d_min , 1.5 / i_nb_channels ); 
     293        i_next_atomic_operation += 2; 
     294        i_source_channel_offset++; 
     295    } 
     296    if( i_physical_channels & AOUT_CHAN_REARRIGHT ) 
     297    { 
     298        ComputeChannelOperations( p_data , i_rate 
     299                , i_next_atomic_operation , i_source_channel_offset 
     300                , d_x , d_z_rear , d_min , 1.5 / i_nb_channels ); 
     301        i_next_atomic_operation += 2; 
     302        i_source_channel_offset++; 
     303    } 
     304    if( i_physical_channels & AOUT_CHAN_REARCENTER ) 
     305    { 
     306        ComputeChannelOperations( p_data , i_rate 
     307                , i_next_atomic_operation , i_source_channel_offset 
     308                , 0 , -d_z , d_min , 1.5 / i_nb_channels ); 
     309        i_next_atomic_operation += 2; 
     310        i_source_channel_offset++; 
     311    } 
     312    if( i_physical_channels & AOUT_CHAN_CENTER ) 
     313    { 
     314        /* having two center channels increases the spatialization effect */ 
     315        ComputeChannelOperations( p_data , i_rate 
     316                , i_next_atomic_operation , i_source_channel_offset 
     317                , d_x / 5.0 , d_z , d_min , 0.75 / i_nb_channels ); 
     318        i_next_atomic_operation += 2; 
     319        ComputeChannelOperations( p_data , i_rate 
     320                , i_next_atomic_operation , i_source_channel_offset 
     321                , -d_x / 5.0 , d_z , d_min , 0.75 / i_nb_channels ); 
     322        i_next_atomic_operation += 2; 
     323        i_source_channel_offset++; 
     324    } 
     325    if( i_physical_channels & AOUT_CHAN_LFE ) 
     326    { 
     327        ComputeChannelOperations( p_data , i_rate 
     328                , i_next_atomic_operation , i_source_channel_offset 
     329                , 0 , d_z_rear , d_min , 5.0 / i_nb_channels ); 
     330        i_next_atomic_operation += 2; 
     331        i_source_channel_offset++; 
     332    } 
     333 
     334    /* Initialize the overflow buffer 
     335     * we need it because the process induce a delay in the samples */ 
     336    p_data->i_overflow_buffer_size = 0; 
     337    for( i = 0 ; i < p_data->i_nb_atomic_operations ; i++ ) 
     338    { 
     339        if( p_data->i_overflow_buffer_size 
     340                < p_data->p_atomic_operations[i].i_delay * 2 * sizeof (int16_t) ) 
     341        { 
     342            p_data->i_overflow_buffer_size 
     343                = p_data->p_atomic_operations[i].i_delay * 2 * sizeof (int16_t); 
     344        } 
     345    } 
     346    p_data->p_overflow_buffer = malloc( p_data->i_overflow_buffer_size ); 
     347    if( p_data->p_atomic_operations == NULL ) 
     348    { 
     349        msg_Err( p_this, "out of memory" ); 
     350        return -1; 
     351    } 
     352    memset( p_data->p_overflow_buffer, 0 , p_data->i_overflow_buffer_size ); 
     353 
     354    /* end */ 
     355    return 0; 
     356} 
     357 
    100358/***************************************************************************** 
    101359 * OpenFilter 
     
    136394    } 
    137395 
     396    var_Create( p_this, MONO_CFG "mono-downmix", 
     397                VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); 
     398    p_sys->b_downmix = var_GetBool( p_this, MONO_CFG "mono-downmix" ); 
     399 
    138400    var_Create( p_this, MONO_CFG "mono-channel", 
    139401                VLC_VAR_INTEGER | VLC_VAR_DOINHERIT ); 
     
    141403            (unsigned int) var_GetInteger( p_this, MONO_CFG "mono-channel" ); 
    142404 
    143 #if 0 
    144     p_filter->fmt_out.audio.i_physical_channels = AOUT_CHAN_CENTER; 
    145 #else 
    146     p_filter->fmt_out.audio.i_physical_channels = 
     405    if( p_sys->b_downmix ) 
     406    { 
     407        p_filter->fmt_out.audio.i_physical_channels = AOUT_CHAN_CENTER; 
     408    } 
     409    else 
     410    { 
     411        p_filter->fmt_out.audio.i_physical_channels = 
    147412                            (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT); 
    148 #endif 
     413    } 
     414    p_filter->fmt_out.audio.i_channels = aout_FormatNbChannels( &(p_filter->fmt_out.audio) ); 
     415 
    149416    p_filter->fmt_out.audio.i_rate = p_filter->fmt_in.audio.i_rate; 
    150417    p_filter->fmt_out.audio.i_format = p_filter->fmt_out.i_codec; 
     
    152419    p_sys->i_nb_channels = aout_FormatNbChannels( &(p_filter->fmt_in.audio) ); 
    153420    p_sys->i_bitspersample = p_filter->fmt_out.audio.i_bitspersample; 
     421 
     422    p_sys->i_overflow_buffer_size = 0; 
     423    p_sys->p_overflow_buffer = NULL; 
     424    p_sys->i_nb_atomic_operations = 0; 
     425    p_sys->p_atomic_operations = NULL; 
     426 
     427    if( Init( VLC_OBJECT(p_filter), p_filter->p_sys, 
     428              aout_FormatNbChannels( &p_filter->fmt_in.audio ), 
     429              p_filter->fmt_in.audio.i_physical_channels, 
     430              p_filter->fmt_in.audio.i_rate ) < 0 ) 
     431    { 
     432        return VLC_EGENERIC; 
     433    } 
    154434 
    155435    p_filter->pf_audio_filter = Convert; 
     
    175455 
    176456    var_Destroy( p_this, MONO_CFG "mono-channel" ); 
     457    var_Destroy( p_this, MONO_CFG "mono-downmix" ); 
    177458    free( p_sys ); 
    178459} 
     
    186467    aout_buffer_t in_buf, out_buf; 
    187468    block_t *p_out = NULL; 
     469    unsigned int i_samples; 
    188470    int i_out_size; 
    189     unsigned int i_samples; 
    190471 
    191472    if( !p_block || !p_block->i_samples ) 
     
    206487        return NULL; 
    207488    } 
    208  
    209489    p_out->i_samples = (p_block->i_samples / p_filter->p_sys->i_nb_channels) * 
    210                             aout_FormatNbChannels( &(p_filter->fmt_out.audio) ); 
     490                       aout_FormatNbChannels( &(p_filter->fmt_out.audio) ); 
    211491    p_out->i_dts = p_block->i_dts; 
    212492    p_out->i_pts = p_block->i_pts; 
     
    237517    out_buf.i_nb_samples = p_out->i_samples; 
    238518 
    239     i_samples = stereo_to_mono( (aout_instance_t *)p_filter, &aout_filter, 
    240                                 &out_buf, &in_buf ); 
     519    if( p_filter->p_sys->b_downmix ) 
     520    { 
     521        memset( out_buf.p_buffer, 0, i_out_size ); 
     522        stereo2mono_downmix( (aout_instance_t *)p_filter, &aout_filter, 
     523                             &in_buf, &out_buf ); 
     524    } 
     525    else 
     526    { 
     527        i_samples = stereo_to_mono( (aout_instance_t *)p_filter, &aout_filter, 
     528                                    &out_buf, &in_buf ); 
     529    } 
    241530 
    242531    p_out->i_buffer = out_buf.i_nb_bytes; 
     
    247536} 
    248537 
    249 /* stereo_to_mono - mix 2 channels (left,right) into one and play silence on 
    250  * all other channels. 
     538/* stereo2mono_downmix - stereo channels into one mono channel. 
     539 * Code taken from modules/audio_filter/channel_mixer/headphone.c 
     540 * converted from float into int16_t based downmix 
     541 * Written by Boris Dorès <babal@via.ecp.fr> 
    251542 */ 
     543static void stereo2mono_downmix( aout_instance_t * p_aout, aout_filter_t * p_filter, 
     544                            aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf ) 
     545{ 
     546    filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys; 
     547 
     548    int i_input_nb = aout_FormatNbChannels( &p_filter->input ); 
     549    int i_output_nb = aout_FormatNbChannels( &p_filter->output ); 
     550 
     551    int16_t * p_in = (int16_t*) p_in_buf->p_buffer; 
     552    byte_t * p_out; 
     553    byte_t * p_overflow; 
     554    byte_t * p_slide; 
     555 
     556    size_t i_overflow_size;     /* in bytes */ 
     557    size_t i_out_size;          /* in bytes */ 
     558 
     559    unsigned int i, j; 
     560 
     561    int i_source_channel_offset; 
     562    int i_dest_channel_offset; 
     563    unsigned int i_delay; 
     564    double d_amplitude_factor; 
     565 
     566    /* out buffer characterisitcs */ 
     567    p_out_buf->i_nb_samples = p_in_buf->i_nb_samples; 
     568    p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes * i_output_nb / i_input_nb; 
     569    p_out = p_out_buf->p_buffer; 
     570    i_out_size = p_out_buf->i_nb_bytes; 
     571 
     572    if( p_sys != NULL ) 
     573    { 
     574        /* Slide the overflow buffer */ 
     575        p_overflow = p_sys->p_overflow_buffer; 
     576        i_overflow_size = p_sys->i_overflow_buffer_size; 
     577 
     578        memset( p_out, 0, i_out_size ); 
     579        if ( i_out_size > i_overflow_size ) 
     580            memcpy( p_out, p_overflow, i_overflow_size ); 
     581        else 
     582            memcpy( p_out, p_overflow, i_out_size ); 
     583 
     584        p_slide = p_sys->p_overflow_buffer; 
     585        while( p_slide < p_overflow + i_overflow_size ) 
     586        { 
     587            if( p_slide + i_out_size < p_overflow + i_overflow_size ) 
     588            { 
     589                memset( p_slide, 0, i_out_size ); 
     590                if( p_slide + 2 * i_out_size < p_overflow + i_overflow_size ) 
     591                    memcpy( p_slide, p_slide + i_out_size, i_out_size ); 
     592                else 
     593                    memcpy( p_slide, p_slide + i_out_size, 
     594                            p_overflow + i_overflow_size - ( p_slide + i_out_size ) ); 
     595            } 
     596            else 
     597            { 
     598                memset( p_slide, 0, p_overflow + i_overflow_size - p_slide ); 
     599            } 
     600            p_slide += i_out_size; 
     601        } 
     602 
     603        /* apply the atomic operations */ 
     604        for( i = 0; i < p_sys->i_nb_atomic_operations; i++ ) 
     605        { 
     606            /* shorter variable names */ 
     607            i_source_channel_offset 
     608                = p_sys->p_atomic_operations[i].i_source_channel_offset; 
     609            i_dest_channel_offset 
     610                = p_sys->p_atomic_operations[i].i_dest_channel_offset; 
     611            i_delay = p_sys->p_atomic_operations[i].i_delay; 
     612            d_amplitude_factor 
     613                = p_sys->p_atomic_operations[i].d_amplitude_factor; 
     614 
     615            if( p_out_buf->i_nb_samples > i_delay ) 
     616            { 
     617                /* current buffer coefficients */ 
     618                for( j = 0; j < p_out_buf->i_nb_samples - i_delay; j++ ) 
     619                { 
     620                    ((int16_t*)p_out)[ (i_delay+j)*i_output_nb + i_dest_channel_offset ] 
     621                        += p_in[ j * i_input_nb + i_source_channel_offset ] 
     622                           * d_amplitude_factor; 
     623                } 
     624 
     625                /* overflow buffer coefficients */ 
     626                for( j = 0; j < i_delay; j++ ) 
     627                { 
     628                    ((int16_t*)p_overflow)[ j*i_output_nb + i_dest_channel_offset ] 
     629                        += p_in[ (p_out_buf->i_nb_samples - i_delay + j) 
     630                           * i_input_nb + i_source_channel_offset ] 
     631                           * d_amplitude_factor; 
     632                } 
     633            } 
     634            else 
     635            { 
     636                /* overflow buffer coefficients only */ 
     637                for( j = 0; j < p_out_buf->i_nb_samples; j++ ) 
     638                { 
     639                    ((int16_t*)p_overflow)[ (i_delay - p_out_buf->i_nb_samples + j) 
     640                        * i_output_nb + i_dest_channel_offset ] 
     641                        += p_in[ j * i_input_nb + i_source_channel_offset ] 
     642                           * d_amplitude_factor; 
     643                } 
     644            } 
     645        } 
     646    } 
     647    else 
     648    { 
     649        memset( p_out, 0, i_out_size ); 
     650    } 
     651} 
     652 
     653/* Simple stereo to mono mixing. */ 
    252654static unsigned int stereo_to_mono( aout_instance_t * p_aout, aout_filter_t *p_filter, 
    253655                                    aout_buffer_t *p_output, aout_buffer_t *p_input )