mixengine.cpp

来自「symbian 下的helix player源代码」· C++ 代码 · 共 618 行 · 第 1/2 页

CPP
618
字号
        200, 170, 152, 140, 130, 122, 115, 110, 105, 100, 96, 92,
        89, 85, 82, 80, 77, 74, 72, 70, 68, 66, 64, 62,
        60, 59, 57, 55, 54, 52, 51, 49, 48, 47, 46, 44,
        43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32,
        31, 30, 29, 28, 28, 27, 26, 25, 24, 24, 23, 22,
        21, 21, 20, 19, 19, 18, 17, 17, 16, 15, 15, 14,
        14, 13, 12, 12, 11, 11, 10, 10, 9, 9, 8, 8,
        7, 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2,
        1, 1, 0, 0
    } ;

    if (vol > HX_MAX_VOLUME)
      return 0 ;
    else if (vol <= 0)
      return VOLUME_SILENT ;
    else
      return -(INT32)vol2TenthOfDb[vol] ;
}
#endif

HX_RESULT HXAudioSvcMixEngine::MixIntoBuffer(void* pPlayerbuf0, UINT32 ulBufSizeInBytes_4, BOOL &bIsMixBufferDirty)
{
    // our caller's sense of "dirty" is inverted
    bIsMixBufferDirty = !bIsMixBufferDirty ;

    char *pPlayerbuf = (char*)pPlayerbuf0 ; // keep the original around
    BOOL bHadInput = FALSE ;

    // optimization lazy-init of buffers.
    // We only allocate the sample buffers when we really need them (the first
    // time MixIntoBuffer() is called)

    if (!m_pBuffer_1)
    {
        // allocate both buffers
        m_pBuffer_1 = new tAudioSample[m_ulChunkSize_1] ;
        if (!m_pBuffer_1)
            return HXR_OUTOFMEMORY ;

        if (m_pResampler)
        {
            m_pBuffer_3 = new tAudioSample[m_ulBufferSize_3] ;
            if (!m_pBuffer_3)
                return HXR_OUTOFMEMORY ;
        }
    }

    UINT32 nSamplesOutput_4 = ulBufSizeInBytes_4 / m_ulBytesPerSample ;

    // make sure we are being handed right-sized buffers.
    if (nSamplesOutput_4 / m_nChannels_4 * (m_ulBytesPerSample * m_nChannels_4) != ulBufSizeInBytes_4)
    {
        HX_ASSERT(0) ;
        return HXR_FAIL ;
    }

    // tile output into chunks
    while (nSamplesOutput_4)
    {
        // Figure out how many samples we need on the resampler output.
        // If we have left-overs from last time, adjust the tile size
        UINT32 nSamples_3 = MIN(nSamplesOutput_4 / m_nChannels_4 * m_nChannels_2_3, m_ulChunkSize_3) ;

        // how many samples in do we need on input?
        UINT32 nSamples_2 ;
#ifdef HELIX_FEATURE_RESAMPLER
        if (m_pResampler)
            nSamples_2 = m_pResampler->GetMinInput(nSamples_3 - m_nOutputSamplesLeft_3) ;
        else
#endif
        nSamples_2 = (nSamples_3 - m_nOutputSamplesLeft_3) ;
        UINT32 nSamples_1 = nSamples_2 * m_nChannels_1 / m_nChannels_2_3 ;

        // make sure that we don't overflow the input buffer (if we did, that would
        // be a design error)
        HX_ASSERT(nSamples_1 <= m_ulChunkSize_1) ;

        //
        // Phase 1: Get the input
        //

        // get input
        BOOL bHaveInput = m_pCvt->ConvertIntoBuffer(m_pBuffer_1, nSamples_1, m_llTimestamp_1);

        // update the time stamp.
        m_llTimestamp_1 += nSamples_1 ;

        //
        // Phase 2: Downmix if necessary. This might need headroom and create overgain
        // (not implemented yet)
        //

        // downmix if necessary (creates nSamples_2 samples)
        if (bHaveInput && m_nChannels_2_3 != m_nChannels_1)
            (*this.*m_pfDownmix)(m_pBuffer_1, nSamples_1) ;

        //
        // apply any volume changes
        //

#ifdef HELIX_FEATURE_GAINTOOL
        if (bHaveInput)
            gainFeed(m_pBuffer_1, nSamples_2, m_pGaintool) ;
#endif

        //
        // Phase 3: Resample
        //

        // resample, but only if we have data. This is a hack -- it ignores
        // the buffers in the resamplers, and thus looses some data, and time-
        // shifts other data. This needs to be worked out.

        tAudioSample *pResampOutput_3 ;
        if (m_pResampler && bHaveInput)
        {
#ifdef HELIX_FEATURE_RESAMPLER
            // compiler should optimize one of these branches away.
            if (NBITS_PER_AUDIOSAMPLE == 32)
                m_nOutputSamplesLeft_3 += m_pResampler->Resample(m_pBuffer_1, nSamples_2, (signed int*)(m_pBuffer_3 + m_nOutputSamplesLeft_3) ) ;
            else
                m_nOutputSamplesLeft_3 += m_pResampler->Resample(m_pBuffer_1, nSamples_2, (signed short*)(m_pBuffer_3 + m_nOutputSamplesLeft_3) ) ;

            // assert that the resampler did not write out-of-bounds
            HX_ASSERT(m_nOutputSamplesLeft_3 <= m_ulBufferSize_3) ;

            // assert that we got at least nSamples_3 samples
            HX_ASSERT(m_nOutputSamplesLeft_3 >= nSamples_3) ;

            pResampOutput_3 = m_pBuffer_3 ;
#endif
        }
        else // estimate the resampler output.
        {
            m_ulResamplerPhase += (nSamples_2 / m_nChannels_2_3) * m_ulSampleRate_3_4 ;
            int sampleFramesOut = m_ulResamplerPhase / m_ulSampleRate_1_2 ;
            m_ulResamplerPhase -= sampleFramesOut * m_ulSampleRate_1_2 ;

            m_nOutputSamplesLeft_3 += sampleFramesOut * m_nChannels_2_3 ;
            pResampOutput_3 = m_pResampler ? m_pBuffer_3 : m_pBuffer_1 ; // pass-through
        }

        // m_nOutputSamplesLeft_3 is the total number of resampled samples (including leftovers
        // from the last time around). Do all further DSP only on nSamples_3 samples, leaving
        // any leftovers for the next time.

#ifdef HELIX_FEATURE_CROSSFADE
        // We apply the crossfade even if we won't use the data, in order to
        // kick its timestamp keeping forward.
        // The performance impact should be negligible, though, since we won't be
        // in crossfades most of the time.

        //
        // if we are at the start of a fade, notify the xfader
        //

        //
        // m_llTimestamp                         ts+nsamples
        // +-------------------------------------+ incoming
        //                  XFade
        //                   |
        // nSamplesBeforeFade nSamplesInFade

        //
        //       m_llTimestamp                         ts+nsamples
        //       +-------------------------------------+ incoming
        // XFade
        //   |------V----------------------------------|
        //       nSamplesInFade
        //  nSamplesBeforeFade  < 0

        INT64 nSamplesBeforeFade = m_llFadeStart - m_llTimestamp_3 ;
        INT64 nSamplesInFade     = nSamples_3 - nSamplesBeforeFade ;

        if (nSamplesBeforeFade >= 0 // fade starts after this segment start
            && nSamplesInFade > 0) // fade starts before this segment end
        {
            // time to start an XFade
            m_bPastXFade = TRUE ;
            XFader_start(m_ulXFadeSamples, m_pXFader) ;
        }

        // if we have passed the X-Fade point, we always run the signal through
        // the XFader. Since it has a fast path when the XFade is done, this is
        // not a resource drain.

        if (m_bPastXFade)
        {
            if (nSamplesBeforeFade < 0) // fade was started earlier
            {
                nSamplesInFade += nSamplesBeforeFade ; // == nSamples_3
                nSamplesBeforeFade = 0 ;
            }
            HX_ASSERT( nSamplesInFade > 0 );

            if (XFader_active(m_pXFader))
                Fader_feed(pResampOutput_3 + nSamplesBeforeFade, (INT32)nSamplesInFade, m_eCrossFadeDirection == FADE_OUT, m_pXFader) ;
        }
#endif

        //
        // Phase 3.5: Run the limiter if needed
        //

#ifdef HELIX_FEATURE_LIMITER
        if (m_pLimiter && NBITS_PER_AUDIOSAMPLE == 32)
        {
            LimiterProcess((int*)pResampOutput_3, nSamples_3, m_pLimiter);
        }
        else
#endif
        {
            // TODO: insert clipping code
        }

        //
        // Phase 4: Mix into the output buffer.
        //

        UINT32 nSamples_4 = nSamples_3 / m_nChannels_2_3 * m_nChannels_4 ;

        if (bHaveInput)
        {
            if (!bHadInput && bIsMixBufferDirty)
            {
                // if we did not have input earlier, but we now receive data, we need to clean out
                // the parts that have not been touched so far.
                memset(pPlayerbuf0,0,pPlayerbuf - (char*)pPlayerbuf0) ;
            }

            // and mix into output (mix) buffer
            switch (m_ulBytesPerSample)
            {
            case 2:
                upmix(pResampOutput_3, (INT16*)pPlayerbuf, m_upmixMachine, nSamples_3, bIsMixBufferDirty) ;
                break ;
            case 4:
                upmix(pResampOutput_3, (INT32*)pPlayerbuf, m_upmixMachine, nSamples_3, bIsMixBufferDirty) ;
                break ;
            }

            // if we have input anywhere, the buffer is not "dirty" anymore.
            bHadInput = TRUE ;
        }
        else
        {
            if (bHadInput && bIsMixBufferDirty)
            {
                // if we did have input earlier, but do not now, we need to clean the output
                // buffer (because it will not be marked "dirty" anymore).
                memset(pPlayerbuf, 0, nSamples_4 * m_ulBytesPerSample) ;
            }
        }

        // save left-over samples
        m_nOutputSamplesLeft_3 -= nSamples_3 ;
        m_llTimestamp_3        += nSamples_3 ;

        // if there is no resampler, there should be no left-over samples
        if (!m_pResampler) HX_ASSERT(m_nOutputSamplesLeft_3 == 0) ;

        // if left-over samples
        if (m_nOutputSamplesLeft_3)
            memcpy(m_pBuffer_3, m_pBuffer_3 + nSamples_3, m_nOutputSamplesLeft_3 * sizeof(*m_pBuffer_3)) ;

        nSamplesOutput_4 -= nSamples_4 ;
        pPlayerbuf += nSamples_4 * m_ulBytesPerSample ;
    }

    // if we had input anywhere within this function, the buffer is not dirty anymore.

    bIsMixBufferDirty &= !bHadInput ;

    bIsMixBufferDirty = !bIsMixBufferDirty ;

    return HXR_OK ;
}

HX_RESULT HXAudioSvcMixEngine::SetCrossFade(
    enum eCrossfadeDirection inOut, // FADE_IN and FADE_OUT
    INT64 llStarttimeInSamples, // output side!
    INT64 llEndtimeInSamples
)
{
#if defined(HELIX_FEATURE_CROSSFADE)
    m_eCrossFadeDirection = inOut ;

    HX_ASSERT(llStarttimeInSamples % m_nChannels_4 == 0 &&
              llEndtimeInSamples   % m_nChannels_4 == 0 ) ;

    m_llFadeStart = llStarttimeInSamples ; // both are pre-resampler

    if (llEndtimeInSamples - llStarttimeInSamples > INT_MAX ||
        llEndtimeInSamples - llStarttimeInSamples < 0)
    {
        // we don't support such long fades
        return HXR_FAIL ;
    }
    // duration is in part 3 samples
    m_ulXFadeSamples = (INT32)(llEndtimeInSamples - llStarttimeInSamples) / m_nChannels_4 * m_nChannels_2_3 ;

    m_bPastXFade = FALSE ;

    return HXR_OK ;
#else
    return HXR_NOTIMPL ;
#endif
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?