Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 18 additions & 10 deletions src/audio/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
option(LIBSCRATCHCPP_AUDIO_SUPPORT "Audio support" ON)

add_library(scratchcpp-audio STATIC)
set(MINIAUDIO_SRC thirdparty/miniaudio)
set(MINIAUDIO_SRC internal/thirdparty/miniaudio)

if (LIBSCRATCHCPP_AUDIO_SUPPORT)
add_library(miniaudio STATIC
Expand All @@ -16,23 +16,31 @@ endif()
target_sources(scratchcpp-audio
PUBLIC
iaudioplayer.h
iaudioplayerfactory.h
audioplayerfactory.cpp
audioplayerfactory.h
iaudiooutput.h
audiooutput.cpp
audiooutput.h
iaudioinput.h
audioinput.h
audioinput.cpp
iaudioloudness.h
)

if (LIBSCRATCHCPP_AUDIO_SUPPORT)
target_sources(scratchcpp-audio
PUBLIC
audioengine.cpp
audioengine.h
audioplayer.cpp
audioplayer.h
internal/audioengine.cpp
internal/audioengine.h
internal/audioplayer.cpp
internal/audioplayer.h
internal/audioloudness.cpp
internal/audioloudness.h
)
else()
target_sources(scratchcpp-audio
PUBLIC
audioplayerstub.cpp
audioplayerstub.h
internal/audioplayerstub.cpp
internal/audioplayerstub.h
internal/audioloudnessstub.cpp
internal/audioloudnessstub.h
)
endif()
35 changes: 35 additions & 0 deletions src/audio/audioinput.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// SPDX-License-Identifier: Apache-2.0

#include "audioinput.h"

#ifdef LIBSCRATCHCPP_AUDIO_SUPPORT
#include "internal/audioloudness.h"
#else
#include "internal/audioloudnessstub.h"
#endif

using namespace libscratchcpp;

std::shared_ptr<IAudioInput> AudioInput::m_instance = std::make_shared<AudioInput>();

AudioInput::AudioInput()
{
}

std::shared_ptr<IAudioInput> AudioInput::instance()
{
return m_instance;
}

std::shared_ptr<IAudioLoudness> AudioInput::audioLoudness() const
{
if (!m_audioLoudness) {
#ifdef LIBSCRATCHCPP_AUDIO_SUPPORT
m_audioLoudness = std::make_shared<AudioLoudness>();
#else
m_audioLoudness = std::make_shared<AudioLoudnessStub>();
#endif
}

return m_audioLoudness;
}
27 changes: 27 additions & 0 deletions src/audio/audioinput.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: Apache-2.0

#pragma once

#include <memory>

#include "iaudioinput.h"

namespace libscratchcpp
{

class AudioInput : public IAudioInput
{
public:
AudioInput();

static std::shared_ptr<IAudioInput> instance();

std::shared_ptr<IAudioLoudness> audioLoudness() const override;

private:
static std::shared_ptr<IAudioInput> m_instance;

mutable std::shared_ptr<IAudioLoudness> m_audioLoudness;
};

} // namespace libscratchcpp
31 changes: 31 additions & 0 deletions src/audio/audiooutput.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: Apache-2.0

#include "audiooutput.h"

#ifdef LIBSCRATCHCPP_AUDIO_SUPPORT
#include "internal/audioplayer.h"
#else
#include "internal/audioplayerstub.h"
#endif

using namespace libscratchcpp;

std::shared_ptr<IAudioOutput> AudioOutput::m_instance = std::make_shared<AudioOutput>();

AudioOutput::AudioOutput()
{
}

std::shared_ptr<IAudioOutput> AudioOutput::instance()
{
return m_instance;
}

std::shared_ptr<IAudioPlayer> AudioOutput::createAudioPlayer() const
{
#ifdef LIBSCRATCHCPP_AUDIO_SUPPORT
return std::make_shared<AudioPlayer>();
#else
return std::make_shared<AudioPlayerStub>();
#endif
}
23 changes: 23 additions & 0 deletions src/audio/audiooutput.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: Apache-2.0

#pragma once

#include "iaudiooutput.h"

namespace libscratchcpp
{

class AudioOutput : public IAudioOutput
{
public:
AudioOutput();

static std::shared_ptr<IAudioOutput> instance();

std::shared_ptr<IAudioPlayer> createAudioPlayer() const override;

private:
static std::shared_ptr<IAudioOutput> m_instance;
};

} // namespace libscratchcpp
31 changes: 0 additions & 31 deletions src/audio/audioplayerfactory.cpp

This file was deleted.

22 changes: 0 additions & 22 deletions src/audio/audioplayerfactory.h

This file was deleted.

21 changes: 21 additions & 0 deletions src/audio/iaudioinput.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// SPDX-License-Identifier: Apache-2.0

#pragma once

#include <memory>

namespace libscratchcpp
{

class IAudioLoudness;

class IAudioInput
{

public:
virtual ~IAudioInput() { }

virtual std::shared_ptr<IAudioLoudness> audioLoudness() const = 0;
};

} // namespace libscratchcpp
16 changes: 16 additions & 0 deletions src/audio/iaudioloudness.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: Apache-2.0

#pragma once

namespace libscratchcpp
{

class IAudioLoudness
{
public:
virtual ~IAudioLoudness() { }

virtual int getLoudness() const = 0;
};

} // namespace libscratchcpp
6 changes: 3 additions & 3 deletions src/audio/iaudioplayerfactory.h → src/audio/iaudiooutput.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ namespace libscratchcpp

class IAudioPlayer;

class IAudioPlayerFactory
class IAudioOutput
{
public:
virtual ~IAudioPlayerFactory() { }
virtual ~IAudioOutput() { }

virtual std::shared_ptr<IAudioPlayer> create() const = 0;
virtual std::shared_ptr<IAudioPlayer> createAudioPlayer() const = 0;
};

} // namespace libscratchcpp
File renamed without changes.
File renamed without changes.
87 changes: 87 additions & 0 deletions src/audio/internal/audioloudness.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// SPDX-License-Identifier: Apache-2.0

#include <miniaudio.h>
#include <atomic>
#include <cmath>
#include <iostream>

#include "audioloudness.h"

using namespace libscratchcpp;

static std::atomic<int> loudness = -1;
static float lastValue = 0.0f;

static void data_callback(ma_device *pDevice, void *pOutput, const void *pInput, ma_uint32 frameCount)
{
const float *pMicDataArray = static_cast<const float *>(pInput);

// https://github.com/scratchfoundation/scratch-audio/blob/068aca613604e39b2adbe785b17931cc43eec35f/src/Loudness.js#L36-L80
// Compute the RMS of the sound
float sum = 0.0f;

for (ma_uint32 i = 0; i < frameCount; i++) {
float value = pMicDataArray[i];
sum += std::pow(value, 2) / 20.0f; // TODO: Convert the value properly (it's different than in JS)
}

float rms = std::sqrt(sum / static_cast<float>(frameCount));

// Smooth the value, if it is descending
if (lastValue != 0.0f) {
rms = std::max(rms, lastValue * 0.6f);
}

lastValue = rms;

// Scale the measurement
rms *= 1.63f;
rms = std::sqrt(rms);
// Scale it up to 0-100 and round
rms = std::round(rms * 100.0f);
// Prevent it from going above 100
rms = std::min(rms, 100.0f);

loudness = rms;
}

AudioLoudness::AudioLoudness()
{
ma_device_config deviceConfig = ma_device_config_init(ma_device_type_capture);
deviceConfig.capture.format = ma_format_f32;
deviceConfig.capture.channels = 1; // mono
deviceConfig.sampleRate = 44100;
deviceConfig.periodSizeInFrames = 2048;
deviceConfig.dataCallback = data_callback;
deviceConfig.pUserData = NULL;

m_device = new ma_device;

if (ma_device_init(NULL, &deviceConfig, m_device) != MA_SUCCESS) {
std::cerr << "Failed to initialize audio capture device." << std::endl;
delete m_device;
m_device = nullptr;
return;
}

if (ma_device_start(m_device) != MA_SUCCESS) {
std::cerr << "Failed to start audio capture device." << std::endl;
ma_device_uninit(m_device);
delete m_device;
m_device = nullptr;
return;
}
}

AudioLoudness::~AudioLoudness()
{
if (m_device) {
ma_device_uninit(m_device);
delete m_device;
}
}

int AudioLoudness::getLoudness() const
{
return loudness;
}
24 changes: 24 additions & 0 deletions src/audio/internal/audioloudness.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// SPDX-License-Identifier: Apache-2.0

#pragma once

#include "../iaudioloudness.h"

struct ma_device;

namespace libscratchcpp
{

class AudioLoudness : public IAudioLoudness
{
public:
AudioLoudness();
~AudioLoudness();

int getLoudness() const override;

private:
ma_device *m_device = nullptr;
};

} // namespace libscratchcpp
Loading