📄 taudiofilterheadphone.cpp
字号:
/*
* Copyright (c) 2004-2006 Milan Cutka
* based on VideoLAN headphone virtual spatialization channel mixer module by Boris Dor鑣
* HRTF by ylai
*
* 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 St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "stdafx.h"
#include "TaudioFilterHeadphone.h"
#include "TmixerSettings.h"
#include "firfilter.h"
#include "TfirSettings.h"
TaudioFilterHeadphone::TaudioFilterHeadphone(IffdshowBase *Ideci,Tfilters *Iparent):TaudioFilter(Ideci,Iparent)
{
oldfmt.freq=0;olddim=-1;
p_sys=NULL;
inited=false;
}
void TaudioFilterHeadphone::done(void)
{
if (p_sys)
{
if (p_sys->p_overflow_buffer) free(p_sys->p_overflow_buffer);
if (p_sys->p_atomic_operations) free(p_sys->p_atomic_operations);
free(p_sys);p_sys=NULL;
}
}
/*****************************************************************************
* 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
* */
void TaudioFilterHeadphone::aout_filter_sys_t::ComputeChannelOperations (
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_atomic_operations[i_next_atomic_operation]
.i_source_channel_offset = i_source_channel_offset;
p_atomic_operations[i_next_atomic_operation]
.i_dest_channel_offset = 0;/* left */
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_atomic_operations[i_next_atomic_operation]
.d_amplitude_factor = d_channel_amplitude_factor * 1.1 / 2;
}
else if ( d_x > 0 )
{
p_atomic_operations[i_next_atomic_operation]
.d_amplitude_factor = d_channel_amplitude_factor * 0.9 / 2;
}
else
{
p_atomic_operations[i_next_atomic_operation]
.d_amplitude_factor = d_channel_amplitude_factor / 2;
}
/* Right ear */
p_atomic_operations[i_next_atomic_operation + 1]
.i_source_channel_offset = i_source_channel_offset;
p_atomic_operations[i_next_atomic_operation + 1]
.i_dest_channel_offset = 1;/* right */
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_atomic_operations[i_next_atomic_operation + 1]
.d_amplitude_factor = d_channel_amplitude_factor * 0.9 / 2;
}
else if ( d_x > 0 )
{
p_atomic_operations[i_next_atomic_operation + 1]
.d_amplitude_factor = d_channel_amplitude_factor * 1.1 / 2;
}
else
{
p_atomic_operations[i_next_atomic_operation + 1]
.d_amplitude_factor = d_channel_amplitude_factor / 2;
}
}
int TaudioFilterHeadphone::aout_filter_sys_t::Init(const TsampleFormat &fmt,const TmixerSettings *cfg)
{
double d_x = cfg->headphone_dim;//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;
/* Number of elementary operations */
i_nb_atomic_operations = fmt.nchannels * 2;
p_atomic_operations = (atomic_operation_t*)malloc ( sizeof(atomic_operation_t)
* i_nb_atomic_operations );
/* For each virtual speaker, computes elementary wave propagation time
* to each ear */
i_next_atomic_operation = 0;
i_source_channel_offset = 0;
for (unsigned int ch=0;ch<fmt.nchannels;ch++)
if ( fmt.speakers[ch] == SPEAKER_FRONT_LEFT)
{
ComputeChannelOperations ( fmt.freq
, i_next_atomic_operation , i_source_channel_offset
, -d_x , d_z , 2.0 / fmt.nchannels );
i_next_atomic_operation += 2;
i_source_channel_offset++;
}
else if ( fmt.speakers[ch] == SPEAKER_FRONT_RIGHT )
{
ComputeChannelOperations ( fmt.freq
, i_next_atomic_operation , i_source_channel_offset
, d_x , d_z , 2.0 / fmt.nchannels );
i_next_atomic_operation += 2;
i_source_channel_offset++;
}
else if ( fmt.speakers[ch] == SPEAKER_BACK_LEFT )
{
ComputeChannelOperations ( fmt.freq
, i_next_atomic_operation , i_source_channel_offset
, -d_x , d_z_rear , 1.5 / fmt.nchannels );
i_next_atomic_operation += 2;
i_source_channel_offset++;
}
else if ( fmt.speakers[ch] == SPEAKER_BACK_RIGHT )
{
ComputeChannelOperations ( fmt.freq
, i_next_atomic_operation , i_source_channel_offset
, d_x , d_z_rear , 1.5 / fmt.nchannels );
i_next_atomic_operation += 2;
i_source_channel_offset++;
}
else if ( fmt.speakers[ch] == SPEAKER_BACK_CENTER )
{
ComputeChannelOperations ( fmt.freq
, i_next_atomic_operation , i_source_channel_offset
, 0 , -d_z , 1.5 / fmt.nchannels );
i_next_atomic_operation += 2;
i_source_channel_offset++;
}
else if ( fmt.speakers[ch] == SPEAKER_FRONT_CENTER )
{
ComputeChannelOperations ( fmt.freq
, i_next_atomic_operation , i_source_channel_offset
, 0 , d_z , 1.5 / fmt.nchannels );
i_next_atomic_operation += 2;
i_source_channel_offset++;
}
else if ( fmt.speakers[ch] == SPEAKER_LOW_FREQUENCY )
{
ComputeChannelOperations ( fmt.freq
, i_next_atomic_operation , i_source_channel_offset
, 0 , d_z_rear , 5.0 / fmt.nchannels );
i_next_atomic_operation += 2;
i_source_channel_offset++;
}
else if ( fmt.speakers[ch] == SPEAKER_SIDE_LEFT )
{
ComputeChannelOperations ( fmt.freq
, i_next_atomic_operation , i_source_channel_offset
, -d_x , 0 , 1.5 / fmt.nchannels );
i_next_atomic_operation += 2;
i_source_channel_offset++;
}
else if ( fmt.speakers[ch] == SPEAKER_SIDE_RIGHT )
{
ComputeChannelOperations ( fmt.freq
, i_next_atomic_operation , i_source_channel_offset
, d_x , 0 , 1.5 / fmt.nchannels );
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 */
i_overflow_buffer_size = 0;
for (unsigned int i= 0 ; i < i_nb_atomic_operations ; i++ )
{
if ( i_overflow_buffer_size
< p_atomic_operations[i].i_delay * ((fmt.nchannels >= 2) ? fmt.nchannels : 2)
* sizeof (float) )
{
i_overflow_buffer_size
= p_atomic_operations[i].i_delay * ((fmt.nchannels >= 2) ? fmt.nchannels : 2)
* sizeof (float);
}
}
p_overflow_buffer = (byte_t*)malloc ( i_overflow_buffer_size );
memset ( p_overflow_buffer , 0 , i_overflow_buffer_size );
/* end */
return 0;
}
bool TaudioFilterHeadphone::getOutputFmt(TsampleFormat &fmt,const TfilterSettingsAudio *cfg)
{
if (super::getOutputFmt(fmt,cfg))
{
fmt.setChannels(2);
return true;
}
else
return false;
}
HRESULT TaudioFilterHeadphone::process(TfilterQueue::iterator it,TsampleFormat &fmt,void *samples0,size_t numsamples,const TfilterSettingsAudio *cfg0)
{
const TmixerSettings *cfg=(const TmixerSettings*)cfg0;
if (!p_sys || oldfmt!=fmt || olddim!=cfg->headphone_dim)
{
oldfmt=fmt;olddim=cfg->headphone_dim;
done();
/* Allocate the memory needed to store the module's structure */
p_sys=(aout_filter_sys_t*)malloc(sizeof(aout_filter_sys_t));
p_sys->i_overflow_buffer_size=0;
p_sys->p_overflow_buffer=NULL;
p_sys->i_nb_atomic_operations=0;
p_sys->p_atomic_operations=NULL;
inited=p_sys->Init(fmt,cfg)>=0;
}
if (inited)
{
float *p_in=(float*)init(cfg,fmt,samples0,numsamples);
unsigned int i_input_nb=fmt.nchannels;
fmt.setChannels(2);
float *p_out=(float*)alloc_buffer(fmt,numsamples,buf);
unsigned int i_output_nb=fmt.nchannels;
/* Slide the overflow buffer */
byte_t *p_overflow = p_sys->p_overflow_buffer;
size_t i_overflow_size = p_sys->i_overflow_buffer_size;
size_t i_out_size=numsamples*fmt.blockAlign();
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 );
byte_t *p_slide = 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 ( unsigned int i = 0 ; i < p_sys->i_nb_atomic_operations ; i++ )
{
/* shorter variable names */
int i_source_channel_offset = p_sys->p_atomic_operations[i].i_source_channel_offset;
int i_dest_channel_offset = p_sys->p_atomic_operations[i].i_dest_channel_offset;
unsigned int i_delay = p_sys->p_atomic_operations[i].i_delay;
double d_amplitude_factor = p_sys->p_atomic_operations[i].d_amplitude_factor;
if ( numsamples > i_delay )
{
unsigned int j;
/* current buffer coefficients */
for ( j = 0 ; j < numsamples - i_delay ; j++ )
{
p_out[ (i_delay+j)*i_output_nb + i_dest_channel_offset ]
+= float(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 ]
+= float(p_in[ (numsamples - i_delay + j)
* i_input_nb + i_source_channel_offset ]
* d_amplitude_factor);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -