예제 #1
0
    void DspTempo::Process(DspChunk& chunk)
    {
        if (!m_active || chunk.IsEmpty())
            return;

        assert(chunk.GetRate() == m_rate);
        assert(chunk.GetChannelCount() == m_channels);

        // DirectShow speed is in double precision, SoundTouch operates in single.
        // We have to adjust it dynamically.
        AdjustTempo();

        DspChunk::ToFloat(chunk);

        m_stouch.putSamples((const float*)chunk.GetData(), (uint32_t)chunk.GetFrameCount());

        DspChunk output(DspFormat::Float, m_channels, m_stouch.numSamples(), m_rate);

        uint32_t done = m_stouch.receiveSamples((float*)output.GetData(), (uint32_t)output.GetFrameCount());
        assert(done == output.GetFrameCount());
        output.ShrinkTail(done);

        auto& outSamples = (m_ftempo == m_ftempo1) ? m_outSamples1 : m_outSamples2;
        outSamples += done;

        chunk = std::move(output);
    }
예제 #2
0
    DspChunk DspRate::ProcessChunk(soxr_t soxr, DspChunk& chunk)
    {
        assert(soxr);
        assert(!chunk.IsEmpty());
        assert(chunk.GetRate() == m_inputRate);
        assert(chunk.GetChannelCount() == m_channels);

        DspChunk::ToFloat(chunk);

        size_t outputFrames = (size_t)(2 * (uint64_t)chunk.GetFrameCount() * m_outputRate / m_inputRate);
        DspChunk output(DspFormat::Float, chunk.GetChannelCount(), outputFrames, m_outputRate);

        size_t inputDone = 0;
        size_t outputDone = 0;
        soxr_process(soxr, chunk.GetData(), chunk.GetFrameCount(), &inputDone,
                           output.GetData(), output.GetFrameCount(), &outputDone);
        assert(inputDone == chunk.GetFrameCount());
        output.ShrinkTail(outputDone);

        return output;
    }
예제 #3
0
    void DspBalance::Process(DspChunk& chunk)
    {
        const float balance = m_renderer.GetBalance();
        assert(balance >= -1.0f && balance <= 1.0f);

        if (balance == 0.0f || chunk.IsEmpty() || chunk.GetChannelCount() != 2)
            return;

        DspChunk::ToFloat(chunk);

        auto data = reinterpret_cast<float*>(chunk.GetData());
        const float gain = std::abs(balance);
        for (size_t i = (balance < 0.0f ? 1 : 0), n = chunk.GetSampleCount(); i < n; i += 2)
            data[i] *= gain;
    }
예제 #4
0
    void AudioRenderer::ApplyRateCorrection(DspChunk& chunk)
    {
        CAutoLock objectLock(this);
        assert(m_device);
        assert(!m_device->IsBitstream());
        assert(m_state == State_Running);

        if (chunk.IsEmpty())
            return;

        const REFERENCE_TIME latency = llMulDiv(chunk.GetFrameCount(), OneSecond, chunk.GetRate(), 0) +
                                       m_device->GetStreamLatency() + OneMillisecond * 10;

        const REFERENCE_TIME remaining = m_device->GetEnd() - m_device->GetPosition();

        REFERENCE_TIME deltaTime = 0;

        if (m_live)
        {
            // Rate matching.
            if (remaining > latency)
            {
                size_t dropFrames = (size_t)llMulDiv(m_device->GetWaveFormat()->nSamplesPerSec,
                                                     remaining - latency, OneSecond, 0);

                dropFrames = std::min(dropFrames, chunk.GetFrameCount());

                chunk.ShrinkHead(chunk.GetFrameCount() - dropFrames);

                DebugOut("AudioRenderer drop", dropFrames, "frames for rate matching");
            }
        }
        else
        {
            // Clock matching.
            assert(m_externalClock);

            REFERENCE_TIME graphTime, myTime, myStartTime;
            if (SUCCEEDED(m_myClock.GetAudioClockStartTime(&myStartTime)) &&
                SUCCEEDED(m_myClock.GetAudioClockTime(&myTime, nullptr)) &&
                SUCCEEDED(m_graphClock->GetTime(&graphTime)) &&
                myTime > myStartTime)
            {
                myTime -= m_device->GetSilence();

                if (myTime > graphTime)
                {
                    // Pad and adjust backwards.
                    REFERENCE_TIME padTime = myTime - graphTime;
                    assert(padTime >= 0);

                    size_t padFrames = (size_t)llMulDiv(m_device->GetWaveFormat()->nSamplesPerSec,
                                                        padTime, OneSecond, 0);

                    if (padFrames > m_device->GetWaveFormat()->nSamplesPerSec / 33) // ~30ms threshold
                    {
                        DspChunk tempChunk(chunk.GetFormat(), chunk.GetChannelCount(),
                                           chunk.GetFrameCount() + padFrames, chunk.GetRate());

                        size_t padBytes = tempChunk.GetFrameSize() * padFrames;
                        ZeroMemory(tempChunk.GetData(), padBytes);
                        memcpy(tempChunk.GetData() + padBytes, chunk.GetData(), chunk.GetSize());

                        chunk = std::move(tempChunk);

                        REFERENCE_TIME paddedTime = llMulDiv(padFrames, OneSecond,
                                                             m_device->GetWaveFormat()->nSamplesPerSec, 0);

                        m_myClock.OffsetSlavedClock(-paddedTime);
                        padTime -= paddedTime;
                        assert(padTime >= 0);

                        DebugOut("AudioRenderer pad", paddedTime / 10000., "ms for clock matching at",
                                 m_sampleCorrection.GetLastFrameEnd() / 10000., "frame position");
                    }

                    // Correct the rest with variable rate.
                    m_dspRealtimeRate.Adjust(padTime);
                    m_myClock.OffsetSlavedClock(-padTime);
                }
                else if (remaining > latency)
                {
                    // Crop and adjust forwards.
                    assert(myTime <= graphTime);
                    REFERENCE_TIME dropTime = std::min(graphTime - myTime, remaining - latency);
                    assert(dropTime >= 0);

                    size_t dropFrames = (size_t)llMulDiv(m_device->GetWaveFormat()->nSamplesPerSec,
                                                         dropTime, OneSecond, 0);

                    dropFrames = std::min(dropFrames, chunk.GetFrameCount());

                    if (dropFrames > m_device->GetWaveFormat()->nSamplesPerSec / 33) // ~30ms threshold
                    {
                        chunk.ShrinkHead(chunk.GetFrameCount() - dropFrames);

                        REFERENCE_TIME droppedTime = llMulDiv(dropFrames, OneSecond,
                                                              m_device->GetWaveFormat()->nSamplesPerSec, 0);

                        m_myClock.OffsetSlavedClock(droppedTime);
                        dropTime -= droppedTime;
                        assert(dropTime >= 0);

                        DebugOut("AudioRenderer drop", droppedTime / 10000., "ms for clock matching at",
                                 m_sampleCorrection.GetLastFrameEnd() / 10000., "frame position");
                    }

                    // Correct the rest with variable rate.
                    m_dspRealtimeRate.Adjust(-dropTime);
                    m_myClock.OffsetSlavedClock(dropTime);
                }
            }
        }
    }