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);
}
Пример #4
0
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;
}
Пример #5
0
void TmixerSettings::setFormatOut(TsampleFormat &fmt) const
{
    if (out != 16) {
        fmt.setChannels(chConfigs[out].nchannels, chConfigs[out].channelmask);
    }
}
Пример #6
0
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;
}