bool TaudioFilterHeadphone2::getOutputFmt(TsampleFormat &fmt,const TfilterSettingsAudio *cfg) { if (super::getOutputFmt(fmt,cfg)) { fmt.setChannels(2); return true; } else { return false; } }
HRESULT TaudioFilterHeadphone2::process(TfilterQueue::iterator it,TsampleFormat &fmt,void *samples,size_t numsamples,const TfilterSettingsAudio *cfg0) { const TmixerSettings *cfg=(const TmixerSettings*)cfg0; if (!s || oldfmt!=fmt) { oldfmt=fmt; done(); /* MPlayer's 5 channel layout (notation for the variable): * * 0: L (LF), 1: R (RF), 2: Ls (LR), 3: Rs (RR), 4: C (CF), matrix * encoded: Cs (CR) * * or: L = left, C = center, R = right, F = front, R = rear*/ indexes[0]=fmt.findSpeaker(SPEAKER_FRONT_LEFT); indexes[1]=fmt.findSpeaker(SPEAKER_FRONT_RIGHT); indexes[2]=fmt.findSpeaker(SPEAKER_BACK_LEFT); indexes[3]=fmt.findSpeaker(SPEAKER_BACK_RIGHT); indexes[4]=fmt.findSpeaker(SPEAKER_FRONT_CENTER); indexes[5]=fmt.findSpeaker(SPEAKER_LOW_FREQUENCY); //indexes[6]=fmt.findSpeaker(SPEAKER_BACK_CENTER); //indexes[7]=fmt.findSpeaker(SPEAKER_SIDE_LEFT); //indexes[8]=fmt.findSpeaker(SPEAKER_SIDE_RIGHT); s=new af_hrtf_s(fmt); } float *inbuf=(float*)init(cfg,fmt,samples,numsamples); // Input audio data float *end=inbuf+numsamples*fmt.nchannels; // Loop end fmt.setChannels(2); float *out=(float*)(samples=alloc_buffer(fmt,numsamples,buf)); const int dblen = s->dlbuflen, hlen = s->hrflen, blen = s->basslen; while(inbuf < end) { const int k = s->cyc_pos; for (int i=0 ; i<6 /* 9 */ ; i++) { in[i]=indexes[i]!=-1 ? inbuf[indexes[i]] : 0.0f; } s->update_ch(in, k); /* Simulate a 7.5 ms -20 dB echo of the center channel in the front channels (like reflection from a room wall) - a kind of psycho-acoustically "cheating" to focus the center front channel, which is normally hard to be perceived as front */ static const float CFECHOAMPL=M17_0DB; /* Center front echo amplitude */ s->lf[k] += CFECHOAMPL * s->cf[(k + CFECHODELAY) % s->dlbuflen]; s->rf[k] += CFECHOAMPL * s->cf[(k + CFECHODELAY) % s->dlbuflen]; float common,left,right; common = conv(dblen, hlen, &s->cf[0], &s->cf_ir[0], k + s->cf_o); left = ( conv(dblen, hlen, &s->lf[0], s->af_ir, k + s->af_o) + conv(dblen, hlen, &s->rf[0], s->of_ir, k + s->of_o) + conv(dblen, hlen, &s->lr[0], s->ar_ir, k + s->ar_o) + conv(dblen, hlen, &s->rr[0], s->or_ir, k + s->or_o) + common); right = ( conv(dblen, hlen, &s->rf[0], s->af_ir, k + s->af_o) + conv(dblen, hlen, &s->lf[0], s->of_ir, k + s->of_o) + conv(dblen, hlen, &s->rr[0], s->ar_ir, k + s->ar_o) + conv(dblen, hlen, &s->lr[0], s->or_ir, k + s->or_o) + common); /* Bass compensation for the lower frequency cut of the HRTF. A cross talk of the left and right channel is introduced to match the directional characteristics of higher frequencies. The bass will not have any real 3D perception, but that is OK (note at 180 Hz, the wavelength is about 2 m, and any spatial perception is impossible). */ float left_b = conv(dblen, blen, &s->ba_l[0], s->ba_ir, k); float right_b = conv(dblen, blen, &s->ba_r[0], s->ba_ir, k); left += (1 - BASSCROSS) * left_b + BASSCROSS * right_b; right += (1 - BASSCROSS) * right_b + BASSCROSS * left_b; /* Also mix the LFE channel (if available) */ if(indexes[5]!=-1) { left += in[5] * M3_01DB; right += in[5] * M3_01DB; } /* Amplitude renormalization. */ static const float AMPLNORM=M6_99DB; /* Overall amplitude renormalization */ left *= AMPLNORM; right *= AMPLNORM; /* "Cheating": linear stereo expansion to amplify the 3D perception. Note: Too much will destroy the acoustic space and may even result in headaches. */ float diff = STEXPAND2 * (left - right); out[0] = left + diff; out[1] = right - diff; /* Next sample... */ inbuf += oldfmt.nchannels; out += fmt.nchannels; s->cyc_pos--; if(s->cyc_pos < 0) { s->cyc_pos += dblen; } } return parent->deliverSamples(++it,fmt,samples,numsamples); }
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); } } else { /* overflow buffer coefficients only */ for ( unsigned int j = 0 ; j < numsamples ; j++ ) { ((float*)p_overflow)[ (i_delay - numsamples + j) * i_output_nb + i_dest_channel_offset ] += float(p_in[ j * i_input_nb + i_source_channel_offset ] * d_amplitude_factor); } } } samples0=p_out; } return parent->deliverSamples(++it,fmt,samples0,numsamples); }
void TmixerSettings::setFormatOut(TsampleFormat &outfmt, const TsampleFormat &infmt) const { outfmt.setChannels(out == 16 ? infmt.nchannels : chConfigs[out].nchannels, out == 16 ? infmt.channelmask : chConfigs[out].channelmask); outfmt.dolby = out == 16 ? infmt.dolby : chConfigs[out].dolby; }
void TmixerSettings::setFormatOut(TsampleFormat &fmt) const { if (out != 16) { fmt.setChannels(chConfigs[out].nchannels, chConfigs[out].channelmask); } }
TsampleFormat TmixerMatrix::calc_matrix(const TsampleFormat &infmt, const TmixerSettings *cfg) { TsampleFormat outfmt = infmt; cfg->setFormatOut(outfmt, infmt); DWORD in_ch = infmt.makeChannelMask(); DWORD out_ch = outfmt.makeChannelMask(); int in_nfront = infmt.nfront(); int in_nrear = infmt.nrear(); int in_nside = infmt.nside(); int out_nfront = outfmt.nfront(); int out_nrear = outfmt.nrear(); int out_nside = outfmt.nside(); double clev = cfg->clev / 100.0; // central mix level double slev = cfg->slev / 100.0; // surround mix level double lfelev = cfg->lfelev / 100.0; // lfe mix level if (cfg->customMatrix) for (int i = 0; i < 9; i++) for (int j = 0; j < 9; j++) { matrix[i][j] = ((int (*)[9])&cfg->matrix00)[i][j] / 100000.0; } else { memset(&matrix, 0, sizeof(mixer_matrix_t)); if (infmt.dolby & outfmt.dolby) { // Dolby modes are backwards-compatible matrix[CH_L][CH_L] = 1; matrix[CH_R][CH_R] = 1; } else if (outfmt.dolby) { // Downmix to Dolby Surround/ProLogic/ProLogicII if (in_nfront >= 2) { matrix[CH_L][CH_L] = 1; matrix[CH_R][CH_R] = 1; } if (in_nfront != 2) { matrix[CH_C][CH_L] = 0.7071 * clev; matrix[CH_C][CH_R] = 0.7071 * clev; } if (in_nrear == 1) { matrix[CH_BC][CH_L] = -0.7071 * slev; matrix[CH_BC][CH_R] = +0.7071 * slev; } else if (in_nrear == 2) { switch (outfmt.dolby) { case TsampleFormat::DOLBY_PROLOGICII: matrix[CH_BL][CH_L] = -0.8660 * slev; matrix[CH_BR][CH_L] = -0.5000 * slev; matrix[CH_BL][CH_R] = +0.5000 * slev; matrix[CH_BR][CH_R] = +0.8660 * slev; break; case TsampleFormat::DOLBY_SURROUND: case TsampleFormat::DOLBY_PROLOGIC: default: matrix[CH_BL][CH_L] = -slev; matrix[CH_BR][CH_L] = -slev; matrix[CH_BL][CH_R] = +slev; matrix[CH_BR][CH_R] = +slev; break; } } } else { // A/52 standart mixes // direct route equal channels if (in_ch & out_ch & SPEAKER_FRONT_LEFT) { matrix[CH_L ][CH_L ] = 1.0; } if (in_ch & out_ch & SPEAKER_FRONT_RIGHT) { matrix[CH_R ][CH_R ] = 1.0; } if (in_ch & out_ch & SPEAKER_FRONT_CENTER) { matrix[CH_C ][CH_C ] = clev; } if (in_ch & out_ch & SPEAKER_BACK_LEFT) { matrix[CH_BL][CH_BL] = slev; } if (in_ch & out_ch & SPEAKER_BACK_RIGHT) { matrix[CH_BR][CH_BR] = slev; } if (in_ch & out_ch & SPEAKER_SIDE_LEFT) { matrix[CH_AL][CH_AL] = slev; } if (in_ch & out_ch & SPEAKER_SIDE_RIGHT) { matrix[CH_AR][CH_AR] = slev; } if (in_ch & out_ch & SPEAKER_BACK_CENTER) { matrix[CH_BC][CH_BC] = slev; } // calc matrix for fbw channels if (out_nfront == 1) { if (in_nfront != 1) { matrix[CH_L][CH_M] = LEVEL_3DB; matrix[CH_R][CH_M] = LEVEL_3DB; } if (in_nfront == 3) { matrix[CH_C][CH_M] = clev * LEVEL_PLUS3DB; } if (in_nrear == 1) { matrix[CH_BC][CH_M] = slev * LEVEL_3DB; } else { matrix[CH_BL][CH_M] = slev * LEVEL_3DB; matrix[CH_BR][CH_M] = slev * LEVEL_3DB; matrix[CH_AL][CH_M] = slev * LEVEL_3DB; matrix[CH_AR][CH_M] = slev * LEVEL_3DB; } } else { // not mono modes if (out_nfront == 2) { if (in_nfront == 1) { matrix[CH_M][CH_L] = LEVEL_3DB; matrix[CH_M][CH_R] = LEVEL_3DB; } else if (in_nfront == 3) { matrix[CH_C][CH_L] = clev * LEVEL_3DB; matrix[CH_C][CH_R] = clev * LEVEL_3DB; } } if (in_nrear == 1) { if (out_nrear == 0) { matrix[CH_BC][CH_L] = slev * LEVEL_3DB; matrix[CH_BC][CH_R] = slev * LEVEL_3DB; } else if (out_nrear == 2) { matrix[CH_BC][CH_BL] = slev * LEVEL_3DB; matrix[CH_BC][CH_BR] = slev * LEVEL_3DB; } } else if (in_nrear == 2) { if (out_nrear == 0) { matrix[CH_BL][CH_L] = slev; matrix[CH_BR][CH_R] = slev; } else if (out_nrear == 1) { matrix[CH_BL][CH_BC] = slev * LEVEL_3DB; matrix[CH_BR][CH_BC] = slev * LEVEL_3DB; } } if (in_nside == 2) { if (out_nside == 0 && in_nrear > 0) { if (out_nrear == 2) { matrix[CH_AL][CH_L] = slev * LEVEL_3DB; matrix[CH_AL][CH_BL] = slev * LEVEL_3DB; matrix[CH_AR][CH_R] = slev * LEVEL_3DB; matrix[CH_AR][CH_BR] = slev * LEVEL_3DB; } else if (out_nrear == 1) { matrix[CH_AL][CH_L] = slev * LEVEL_3DB; matrix[CH_AL][CH_BC] = slev * LEVEL_3DB; matrix[CH_AR][CH_R] = slev * LEVEL_3DB; matrix[CH_AR][CH_BC] = slev * LEVEL_3DB; } else { matrix[CH_AL][CH_L] = slev; matrix[CH_AR][CH_R] = slev; } } else if (out_nside == 0 && in_nrear == 0) { if (out_nrear == 2) { matrix[CH_AL][CH_BL] = slev; matrix[CH_AR][CH_BR] = slev; } else if (out_nrear == 1) { matrix[CH_AL][CH_BC] = slev; matrix[CH_AR][CH_BC] = slev; } else { matrix[CH_AL][CH_L] = slev; matrix[CH_AR][CH_R] = slev; } } } } } // Expand stereo & Voice control bool expand_stereo_allowed = cfg->expandStereo && !in_nrear; bool voice_control_allowed = cfg->voiceControl && (in_nfront == 2); if ((voice_control_allowed || expand_stereo_allowed) && !outfmt.dolby) { if (voice_control_allowed && out_nfront != 2) { // C' = clev * (L + R) * LEVEL_3DB matrix[CH_L][CH_M] = clev * LEVEL_3DB; matrix[CH_R][CH_M] = clev * LEVEL_3DB; } if (expand_stereo_allowed && in_nfront == 2 && out_nrear) { if (out_nrear == 1) { // S' = slev * (L - R) matrix[CH_L][CH_BC] = + slev; matrix[CH_R][CH_BC] = - slev; } if (out_nrear == 2) { // SL' = slev * 1/2 (L - R) // SR' = slev * 1/2 (R - L) matrix[CH_L][CH_BL] = + 0.5 * slev; matrix[CH_R][CH_BL] = - 0.5 * slev; matrix[CH_L][CH_BR] = - 0.5 * slev; matrix[CH_R][CH_BR] = + 0.5 * slev; } } if (in_nfront != 1) { if (expand_stereo_allowed && voice_control_allowed) { // L' = L * 1/2 (slev + clev) - R * 1/2 (slev - clev) // R' = R * 1/2 (slev + clev) - L * 1/2 (slev - clev) matrix[CH_L][CH_L] = + 0.5 * (slev + clev); matrix[CH_R][CH_L] = - 0.5 * (slev - clev); matrix[CH_L][CH_R] = - 0.5 * (slev - clev); matrix[CH_R][CH_R] = + 0.5 * (slev + clev); } else if (expand_stereo_allowed) { matrix[CH_L][CH_L] = + 0.5 * (slev + 1); matrix[CH_R][CH_L] = - 0.5 * (slev - 1); matrix[CH_L][CH_R] = - 0.5 * (slev - 1); matrix[CH_R][CH_R] = + 0.5 * (slev + 1); } else { // if (voice_control_allowed) matrix[CH_L][CH_L] = + 0.5 * (1 + clev); matrix[CH_R][CH_L] = - 0.5 * (1 - clev); matrix[CH_L][CH_R] = - 0.5 * (1 - clev); matrix[CH_R][CH_R] = + 0.5 * (1 + clev); } } } // LFE mixing if (in_ch & out_ch & SPEAKER_LOW_FREQUENCY) { matrix[CH_LFE][CH_LFE] = lfelev; } // mix LFE into front channels if exists in input // and absent in output if (in_ch & ~out_ch & SPEAKER_LOW_FREQUENCY) { if (out_nfront > 1) { matrix[CH_LFE][CH_L] = lfelev * LEVEL_3DB; matrix[CH_LFE][CH_R] = lfelev * LEVEL_3DB; } else { matrix[CH_LFE][CH_C] = lfelev; } } } if (cfg->normalizeMatrix) { double levels[NCHANNELS] = { 0, 0, 0, 0, 0, 0 }; double max_level; double norm; int i, j; for (i = 0; i < NCHANNELS; i++) for (j = 0; j < NCHANNELS; j++) { levels[i] += matrix[j][i]; } max_level = levels[0]; for (i = 1; i < NCHANNELS; i++) if (levels[i] > max_level) { max_level = levels[i]; } if (max_level > 0) { norm = 1.0 / max_level; } else { norm = 1.0; } for (i = 0; i < NCHANNELS; i++) for (j = 0; j < NCHANNELS; j++) { matrix[j][i] *= norm; } } for (int i = 0; i < NCHANNELS; i++) for (int j = 0; j < NCHANNELS; j++) { matrix[j][i] = limit(matrix[j][i], -4.0, 4.0); } return outfmt; }