Welcome to mirror list, hosted at ThFree Co, Russian Federation.

DspTempo2.cpp « src - github.com/mpc-hc/sanear.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: e20db07b98da080b357ce05ad97b9dfef8eb4ce7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#include "pch.h"
#include "DspTempo2.h"

namespace SaneAudioRenderer
{
    void DspTempo2::Initialize(double tempo, uint32_t rate, uint32_t channels)
    {
        m_stretcher = nullptr;

        m_active = false;
        m_finish = false;

        m_rate = rate;
        m_channels = channels;

        if (tempo != 1.0)
        {
            try
            {
                auto options = RubberBand::RubberBandStretcher::OptionProcessRealTime |
                               RubberBand::RubberBandStretcher::OptionPitchHighQuality;

                m_stretcher = std::make_unique<RubberBand::RubberBandStretcher>(rate, channels, options, 1.0 / tempo);

                m_stretcher->setMaxProcessSize(rate);

                m_active = true;
            }
            catch (std::bad_alloc&)
            {
            }
        }
    }

    bool DspTempo2::Active()
    {
        return m_active;
    }

    void DspTempo2::Process(DspChunk& chunk)
    {
        if (!m_active || chunk.IsEmpty())
            return;

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

        DspChunk::ToFloat(chunk);
        m_stretcher->process(Deinterleave(chunk).data(), chunk.GetFrameCount(), m_finish);

        size_t outputFrames = m_stretcher->available();

        if (outputFrames > 0)
        {

            DspChunk output(DspFormat::Float, m_channels, outputFrames, m_rate);

            size_t outputDone = m_stretcher->retrieve(MarkData(output).data(), outputFrames);
            assert(outputDone == outputFrames);

            Interleave(output);

            chunk = std::move(output);
        }
        else
        {
            chunk = DspChunk();
        }
    }

    void DspTempo2::Finish(DspChunk& chunk)
    {
        if (!m_active)
            return;

        assert(!m_finish);
        m_finish = true;

        Process(chunk);
    }

    DspTempo2::DeinterleavedData DspTempo2::MarkData(DspChunk& chunk)
    {
        assert(!chunk.IsEmpty());
        assert(chunk.GetFormat() == DspFormat::Float);

        DeinterleavedData data = {};

        for (size_t i = 0; i < m_channels; i++)
            data[i] = (float*)(chunk.GetData() + chunk.GetFormatSize() * chunk.GetFrameCount() * i);

        return data;
    }

    DspTempo2::DeinterleavedData DspTempo2::Deinterleave(DspChunk& chunk)
    {
        assert(!chunk.IsEmpty());
        assert(chunk.GetFormat() == DspFormat::Float);

        DspChunk output(DspFormat::Float, m_channels, chunk.GetFrameCount(), m_rate);
        DeinterleavedData outputData = MarkData(output);

        float* inputData = (float*)chunk.GetData();

        for (size_t i = 0, n = chunk.GetSampleCount(); i < n; i++)
            outputData[i % m_channels][i / m_channels] = inputData[i];

        chunk = std::move(output);

        return outputData;
    }

    void DspTempo2::Interleave(DspChunk& chunk)
    {
        assert(!chunk.IsEmpty());
        assert(chunk.GetFormat() == DspFormat::Float);

        DspChunk output(DspFormat::Float, m_channels, chunk.GetFrameCount(), m_rate);
        float* outputData = (float*)output.GetData();

        DeinterleavedData inputData = MarkData(chunk);

        for (size_t channel = 0; channel < m_channels; channel++)
            for (size_t i = 0, n = chunk.GetFrameCount(); i < n; i++)
                outputData[channel + i * m_channels] = inputData[channel][i];

        chunk = std::move(output);
    }
}