Skip to content

Commit 518fa70

Browse files
committed
Add AudioLoudness class
1 parent a821878 commit 518fa70

File tree

6 files changed

+163
-0
lines changed

6 files changed

+163
-0
lines changed

src/audio/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ target_sources(scratchcpp-audio
1919
iaudiooutput.h
2020
audiooutput.cpp
2121
audiooutput.h
22+
iaudioloudness.h
2223
)
2324

2425
if (LIBSCRATCHCPP_AUDIO_SUPPORT)
@@ -28,11 +29,15 @@ if (LIBSCRATCHCPP_AUDIO_SUPPORT)
2829
internal/audioengine.h
2930
internal/audioplayer.cpp
3031
internal/audioplayer.h
32+
internal/audioloudness.cpp
33+
internal/audioloudness.h
3134
)
3235
else()
3336
target_sources(scratchcpp-audio
3437
PUBLIC
3538
internal/audioplayerstub.cpp
3639
internal/audioplayerstub.h
40+
internal/audioloudnessstub.cpp
41+
internal/audioloudnessstub.h
3742
)
3843
endif()

src/audio/iaudioloudness.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
#pragma once
4+
5+
namespace libscratchcpp
6+
{
7+
8+
class IAudioLoudness
9+
{
10+
public:
11+
virtual ~IAudioLoudness() { }
12+
13+
virtual int getLoudness() const = 0;
14+
};
15+
16+
} // namespace libscratchcpp
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
#include <miniaudio.h>
4+
#include <cmath>
5+
#include <iostream>
6+
7+
#include "audioloudness.h"
8+
9+
using namespace libscratchcpp;
10+
11+
static int loudness = -1;
12+
static float lastValue = 0.0f;
13+
14+
static void data_callback(ma_device *pDevice, void *pOutput, const void *pInput, ma_uint32 frameCount)
15+
{
16+
const float *pMicDataArray = static_cast<const float *>(pInput);
17+
18+
// https://github.com/scratchfoundation/scratch-audio/blob/068aca613604e39b2adbe785b17931cc43eec35f/src/Loudness.js#L36-L80
19+
// Compute the RMS of the sound
20+
float sum = 0.0f;
21+
22+
for (ma_uint32 i = 0; i < frameCount; i++) {
23+
float value = pMicDataArray[i];
24+
sum += value * value;
25+
}
26+
27+
float rms = std::sqrt(sum / static_cast<float>(frameCount));
28+
29+
// Smooth the value, if it is descending
30+
if (lastValue != 0.0f) {
31+
rms = std::max(rms, lastValue * 0.6f);
32+
}
33+
34+
lastValue = rms;
35+
36+
// Scale the measurement
37+
rms *= 1.63f;
38+
rms = std::sqrt(rms);
39+
// Scale it up to 0-100 and round
40+
rms = std::round(rms * 100.0f);
41+
// Prevent it from going above 100
42+
rms = std::min(rms, 100.0f);
43+
44+
loudness = rms;
45+
}
46+
47+
AudioLoudness::AudioLoudness()
48+
{
49+
ma_device_config deviceConfig = ma_device_config_init(ma_device_type_capture);
50+
deviceConfig.capture.format = ma_format_f32;
51+
deviceConfig.capture.channels = 1; // mono
52+
deviceConfig.sampleRate = 44100;
53+
deviceConfig.periodSizeInFrames = 2048;
54+
deviceConfig.dataCallback = data_callback;
55+
deviceConfig.pUserData = NULL;
56+
57+
m_device = new ma_device;
58+
59+
if (ma_device_init(NULL, &deviceConfig, m_device) != MA_SUCCESS) {
60+
std::cerr << "Failed to initialize audio capture device." << std::endl;
61+
delete m_device;
62+
m_device = nullptr;
63+
return;
64+
}
65+
66+
if (ma_device_start(m_device) != MA_SUCCESS) {
67+
std::cerr << "Failed to start audio capture device." << std::endl;
68+
ma_device_uninit(m_device);
69+
delete m_device;
70+
m_device = nullptr;
71+
return;
72+
}
73+
}
74+
75+
AudioLoudness::~AudioLoudness()
76+
{
77+
if (m_device) {
78+
ma_device_uninit(m_device);
79+
delete m_device;
80+
}
81+
}
82+
83+
int AudioLoudness::getLoudness() const
84+
{
85+
return loudness;
86+
}

src/audio/internal/audioloudness.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
#pragma once
4+
5+
#include "../iaudioloudness.h"
6+
7+
struct ma_device;
8+
9+
namespace libscratchcpp
10+
{
11+
12+
class AudioLoudness : public IAudioLoudness
13+
{
14+
public:
15+
AudioLoudness();
16+
~AudioLoudness();
17+
18+
int getLoudness() const override;
19+
20+
private:
21+
ma_device *m_device = nullptr;
22+
};
23+
24+
} // namespace libscratchcpp
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
#include "audioloudness.h"
4+
5+
using namespace libscratchcpp;
6+
7+
AudioLoudness::AudioLoudness()
8+
{
9+
}
10+
11+
int AudioLoudness::getLoudness() const
12+
{
13+
return -1;
14+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
#pragma once
4+
5+
#include "../iaudioloudness.h"
6+
7+
namespace libscratchcpp
8+
{
9+
10+
class AudioLoudness : public IAudioLoudness
11+
{
12+
public:
13+
AudioLoudness();
14+
15+
int getLoudness() const override;
16+
};
17+
18+
} // namespace libscratchcpp

0 commit comments

Comments
 (0)