📄 mono.c
字号:
/***************************************************************************** * mono.c : stereo2mono downmixsimple channel mixer plug-in ***************************************************************************** * Copyright (C) 2006 M2X * $Id$ * * Authors: Jean-Paul Saman <jpsaman at m2x dot nl> * * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************//***************************************************************************** * Preamble *****************************************************************************/#ifdef HAVE_CONFIG_H# include "config.h"#endif#include <math.h> /* sqrt */#ifdef HAVE_STDINT_H# include <stdint.h> /* int16_t .. */#elif defined(HAVE_INTTYPES_H)# include <inttypes.h> /* int16_t .. */#endif#ifdef HAVE_UNISTD_H# include <unistd.h>#endif#include <vlc_common.h>#include <vlc_plugin.h>#include <vlc_es.h>#include <vlc_block.h>#include <vlc_filter.h>#include <vlc_aout.h>/***************************************************************************** * Local prototypes *****************************************************************************/static int OpenFilter ( vlc_object_t * );static void CloseFilter ( vlc_object_t * );static block_t *Convert( filter_t *p_filter, block_t *p_block );static unsigned int stereo_to_mono( aout_filter_t *, aout_buffer_t *, aout_buffer_t * );static unsigned int mono( aout_filter_t *, aout_buffer_t *, aout_buffer_t * );static void stereo2mono_downmix( aout_filter_t *, aout_buffer_t *, aout_buffer_t * );/***************************************************************************** * Local 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 filter_sys_t{ bool b_downmix; unsigned int i_nb_channels; /* number of int16_t per sample */ int i_channel_selected; int i_bitspersample; size_t i_overflow_buffer_size;/* in bytes */ uint8_t * p_overflow_buffer; unsigned int i_nb_atomic_operations; struct atomic_operation_t * p_atomic_operations;};#define MONO_DOWNMIX_TEXT N_("Use downmix algorithm")#define MONO_DOWNMIX_LONGTEXT N_("This option selects a stereo to mono " \ "downmix algorithm that is used in the headphone channel mixer. It " \ "gives the effect of standing in a room full of speakers." )#define MONO_CHANNEL_TEXT N_("Select channel to keep")#define MONO_CHANNEL_LONGTEXT N_("This option silences all other channels " \ "except the selected channel. Choose one from (0=left, 1=right, " \ "2=rear left, 3=rear right, 4=center, 5=left front)")static const int pi_pos_values[] = { 0, 1, 2, 4, 8, 5 };static const char *const ppsz_pos_descriptions[] ={ N_("Left"), N_("Right"), N_("Left rear"), N_("Right rear"), N_("Center"), N_("Left front") };/* our internal channel order (WG-4 order) */static const uint32_t pi_channels_out[] ={ AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, AOUT_CHAN_CENTER, AOUT_CHAN_LFE, 0 };#define MONO_CFG "sout-mono-"/***************************************************************************** * Module descriptor *****************************************************************************/vlc_module_begin(); set_description( N_("Audio filter for stereo to mono conversion") ); set_capability( "audio filter2", 2 ); add_bool( MONO_CFG "downmix", true, NULL, MONO_DOWNMIX_TEXT, MONO_DOWNMIX_LONGTEXT, false ); add_integer( MONO_CFG "channel", -1, NULL, MONO_CHANNEL_TEXT, MONO_CHANNEL_LONGTEXT, false ); change_integer_list( pi_pos_values, ppsz_pos_descriptions, NULL ); set_category( CAT_AUDIO ); set_subcategory( SUBCAT_AUDIO_MISC ); set_callbacks( OpenFilter, CloseFilter ); set_shortname( "Mono" );vlc_module_end();/* Init() and ComputeChannelOperations() - * Code taken from modules/audio_filter/channel_mixer/headphone.c * converted from float into int16_t based downmix * Written by Boris Dorès <babal@via.ecp.fr> *//***************************************************************************** * 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 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_compensation_length, double d_channel_amplitude_factor ){ double d_c = 340; /*sound celerity (unit: m/s)*/ double d_compensation_delay = (d_compensation_length-0.1) / d_c * i_rate; /* 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 - d_compensation_delay ); 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 - d_compensation_delay ); 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( vlc_object_t *p_this, struct 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_this, "headphone-dim" ); double d_z = d_x; double d_z_rear = -d_x/3; double d_min = 0; unsigned int i_next_atomic_operation; int i_source_channel_offset; unsigned int i; if( config_GetInt( p_this, "headphone-compensate" ) ) { /* minimal distance to any speaker */ if( i_physical_channels & AOUT_CHAN_REARCENTER ) { d_min = d_z_rear; } else { d_min = d_z; } } /* 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 ) 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 , d_min , 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 , d_min , 2.0 / i_nb_channels ); i_next_atomic_operation += 2; i_source_channel_offset++; } if( i_physical_channels & AOUT_CHAN_MIDDLELEFT ) { ComputeChannelOperations( p_data , i_rate , i_next_atomic_operation , i_source_channel_offset , -d_x , 0 , d_min , 1.5 / i_nb_channels ); i_next_atomic_operation += 2; i_source_channel_offset++; } if( i_physical_channels & AOUT_CHAN_MIDDLERIGHT ) { ComputeChannelOperations( p_data , i_rate , i_next_atomic_operation , i_source_channel_offset , d_x , 0 , d_min , 1.5 / 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 , d_min , 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 , d_min , 1.5 / i_nb_channels ); i_next_atomic_operation += 2; i_source_channel_offset++; } if( i_physical_channels & AOUT_CHAN_REARCENTER ) { ComputeChannelOperations( p_data , i_rate , i_next_atomic_operation , i_source_channel_offset , 0 , -d_z , d_min , 1.5 / i_nb_channels ); i_next_atomic_operation += 2; i_source_channel_offset++; } 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 / 5.0 , d_z , d_min , 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 , d_min , 0.75 / 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 , d_min , 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 * 2 * sizeof (int16_t) ) { p_data->i_overflow_buffer_size = p_data->p_atomic_operations[i].i_delay * 2 * sizeof (int16_t); } } p_data->p_overflow_buffer = malloc( p_data->i_overflow_buffer_size ); if( p_data->p_overflow_buffer == NULL ) { free( p_data->p_atomic_operations ); return -1; } memset( p_data->p_overflow_buffer, 0, p_data->i_overflow_buffer_size ); /* end */ return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -