forked from projectM-visualizer/projectm
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPCM.hpp
executable file
·159 lines (136 loc) · 4.66 KB
/
PCM.hpp
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/**
* projectM -- Milkdrop-esque visualisation SDK
* Copyright (C)2003-2007 projectM Team
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* See 'LICENSE.txt' included within this release
*
*/
/**
* $Id$
*
* Encapsulation of raw sound buffer. Used in beat detection
*
* $Log$
*/
#ifndef _PCM_H
#define _PCM_H
#include <array>
#include <cstdint>
#include <cstdlib>
// FFT_LENGTH is number of magnitude values available from getSpectrum().
// Internally this is generated using 2xFFT_LENGTH samples per channel.
size_t constexpr fftLength = 512;
enum CHANNEL
{
CHANNEL_L = 0,
CHANNEL_0 = 0,
CHANNEL_R = 1,
CHANNEL_1 = 1
};
class Pcm
{
public:
/* maximum number of sound samples that are actually stored. */
static constexpr size_t maxSamples = 2048;
/**
* @brief Adds a mono pcm buffer to the storage
* @param samples The buffer to be added
* @param count The amount of samples in the buffer
*/
void AddMono(const float* samples, size_t count);
void AddMono(const uint8_t* samples, size_t count);
void AddMono(const int16_t* samples, size_t count);
/**
* @brief Adds a stereo pcm buffer to the storage
* @param samples The buffer to be added.
* The channels are expected to be interleaved, LRLR.
* @param count The amount of samples in each channel (not total samples)
*/
void AddStereo(const float* samples, size_t count);
void AddStereo(const uint8_t* samples, size_t count);
void AddStereo(const int16_t* samples, size_t count);
/**
* PCM data
* The returned data will 'wrap' if more than maxsamples are requested.
*/
void GetPcm(float* data, CHANNEL channel, size_t samples) const;
/** Spectrum data
* The returned data will be zero padded if more than FFT_LENGTH values are requested
*/
void GetSpectrum(float* data, CHANNEL channel, size_t samples);
/**
* @brief Resets the auto leveler state.
* Makes sense after pausing/resuming audio or other interruptions.
*/
void ResetAutoLevel();
protected:
// CPP20: Could use a struct for the first 5 params to clarify on call site
// together with designated initializers
template<
size_t lOffset,
size_t rOffset,
size_t stride,
int signalAmplitude,
int signalOffset,
class SampleType>
void AddPcm(const SampleType* samples, size_t count);
// copy data out of the circular PCM buffer
void CopyPcm(float* to, size_t channel, size_t count) const;
void CopyPcm(double* to, size_t channel, size_t count) const;
// update FFT data if new samples are available.
void UpdateFFT();
void UpdateFftChannel(size_t channel);
private:
// mem-usage:
// pcmd 2x2048*4b = 16K
// vdata 2x512x2*8b = 16K
// spectrum 2x512*4b = 4k
// w = 512*8b = 4k
// circular PCM buffer
// adjust "volume" of PCM data as we go, this simplifies everything downstream...
// normalize to range [-1.0,1.0]
std::array<float, maxSamples> m_pcmL{0.f};
std::array<float, maxSamples> m_pcmR{0.f};
size_t m_start{0};
size_t m_newSamples{0};
// raw FFT data
std::array<double, 2 * fftLength> m_freqL{0.0};
std::array<double, 2 * fftLength> m_freqR{0.0};
// magnitude data
std::array<float, fftLength> m_spectrumL{0.f};
std::array<float, fftLength> m_spectrumR{0.f};
std::array<double, fftLength> m_w{0.0};
std::array<int, 34> m_ip{0};
// see https://github.com/projectM-visualizer/projectm/issues/161
class AutoLevel
{
public:
auto UpdateLevel(size_t samples, double sum, double max) -> double;
private:
double m_level{0.01};
// accumulate sample data
size_t m_levelSamples{0};
double m_levelSum{0.0};
double m_levelax{0.0};
double m_l0{-1.0};
double m_l1{-1.0};
double m_l2{-1.0};
};
// state for tracking audio level
double m_level{1.f};
AutoLevel m_leveler{};
};
#endif /** !_PCM_H */