-
-
Notifications
You must be signed in to change notification settings - Fork 454
Expand file tree
/
Copy pathPCM.cpp
More file actions
executable file
·129 lines (105 loc) · 4.05 KB
/
PCM.cpp
File metadata and controls
executable file
·129 lines (105 loc) · 4.05 KB
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 "Audio/PCM.hpp"
#include <mutex>
namespace libprojectM {
namespace Audio {
template<
int signalAmplitude,
int signalOffset,
typename SampleType>
void PCM::AddToBuffer(
SampleType const* const samples,
uint32_t channels,
size_t const sampleCount)
{
if (channels == 0 || sampleCount == 0)
{
return;
}
std::lock_guard<std::mutex> lock(m_pcmMutex);
for (size_t i = 0; i < sampleCount; i++)
{
size_t const bufferOffset = (m_start + i) % AudioBufferSamples;
m_inputBufferL[bufferOffset] = 128.0f * (static_cast<float>(samples[0 + i * channels]) - float(signalOffset)) / float(signalAmplitude);
if (channels > 1)
{
m_inputBufferR[bufferOffset] = 128.0f * (static_cast<float>(samples[1 + i * channels]) - float(signalOffset)) / float(signalAmplitude);
}
else
{
m_inputBufferR[bufferOffset] = m_inputBufferL[bufferOffset];
}
}
m_start = (m_start + sampleCount) % AudioBufferSamples;
}
void PCM::Add(float const* const samples, uint32_t channels, size_t const count)
{
AddToBuffer<1, 0>(samples, channels, count);
}
void PCM::Add(uint8_t const* const samples, uint32_t channels, size_t const count)
{
AddToBuffer<128, 128>(samples, channels, count);
}
void PCM::Add(int16_t const* const samples, uint32_t channels, size_t const count)
{
AddToBuffer<32768, 0>(samples, channels, count);
}
void PCM::UpdateFrameAudioData(double secondsSinceLastFrame, uint32_t frame)
{
// 1. Copy audio data from input buffer (lock to prevent tearing with audio thread writes)
{
std::lock_guard<std::mutex> lock(m_pcmMutex);
CopyNewWaveformData(m_inputBufferL, m_waveformL);
CopyNewWaveformData(m_inputBufferR, m_waveformR);
}
// 2. Update spectrum analyzer data for both channels
UpdateSpectrum(m_waveformL, m_spectrumL);
UpdateSpectrum(m_waveformR, m_spectrumR);
// 3. Align waveforms
m_alignL.Align(m_waveformL);
m_alignR.Align(m_waveformR);
// 4. Update beat detection values
m_bass.Update(m_spectrumL, secondsSinceLastFrame, frame);
m_middles.Update(m_spectrumL, secondsSinceLastFrame, frame);
m_treble.Update(m_spectrumL, secondsSinceLastFrame, frame);
}
auto PCM::GetFrameAudioData() const -> FrameAudioData
{
FrameAudioData data{};
std::copy(m_waveformL.begin(), m_waveformL.begin() + WaveformSamples, data.waveformLeft.begin());
std::copy(m_waveformR.begin(), m_waveformR.begin() + WaveformSamples, data.waveformRight.begin());
std::copy(m_spectrumL.begin(), m_spectrumL.begin() + SpectrumSamples, data.spectrumLeft.begin());
std::copy(m_spectrumR.begin(), m_spectrumR.begin() + SpectrumSamples, data.spectrumRight.begin());
data.bass = m_bass.CurrentRelative();
data.mid = m_middles.CurrentRelative();
data.treb = m_treble.CurrentRelative();
data.bassAtt = m_bass.AverageRelative();
data.midAtt = m_middles.AverageRelative();
data.trebAtt = m_treble.AverageRelative();
data.vol = (data.bass + data.mid + data.treb) * 0.333f;
data.volAtt = (data.bassAtt + data.midAtt + data.trebAtt) * 0.333f;
return data;
}
void PCM::UpdateSpectrum(const WaveformBuffer& waveformData, SpectrumBuffer& spectrumData)
{
std::vector<float> waveformSamples(AudioBufferSamples);
std::vector<float> spectrumValues;
size_t oldI{0};
for (size_t i = 0; i < AudioBufferSamples; i++)
{
// Damp the input into the FFT a bit, to reduce high-frequency noise:
waveformSamples[i] = 0.5f * (waveformData[i] + waveformData[oldI]);
oldI = i;
}
m_fft.TimeToFrequencyDomain(waveformSamples, spectrumValues);
std::copy(spectrumValues.begin(), spectrumValues.end(), spectrumData.begin());
}
void PCM::CopyNewWaveformData(const WaveformBuffer& source, WaveformBuffer& destination)
{
auto const bufferStartIndex = m_start;
for (size_t i = 0; i < AudioBufferSamples; i++)
{
destination[i] = source[(bufferStartIndex + i) % AudioBufferSamples];
}
}
} // namespace Audio
} // namespace libprojectM