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
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ include_directories(thirdparty/spimpl)
target_link_libraries(scratchcpp PRIVATE nlohmann_json::nlohmann_json)
target_link_libraries(scratchcpp PRIVATE utf8cpp)
target_link_libraries(scratchcpp PRIVATE zip)
target_link_libraries(scratchcpp PRIVATE scratchcpp-audio)

if (LIBSCRATCHCPP_NETWORK_SUPPORT)
include(FetchContent)
Expand Down
11 changes: 11 additions & 0 deletions include/scratchcpp/sound.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,24 @@ class LIBSCRATCHCPP_EXPORT Sound : public Asset
public:
Sound(const std::string &name, const std::string &id, const std::string &format);
Sound(const Sound &) = delete;
virtual ~Sound() { }

int rate() const;
void setRate(int newRate);

int sampleCount() const;
void setSampleCount(int newSampleCount);

virtual void setVolume(double volume);

virtual void start();
virtual void stop();

virtual bool isPlaying();

protected:
void processData(unsigned int size, void *data) override;

private:
spimpl::unique_impl_ptr<SoundPrivate> impl;
};
Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ add_subdirectory(blocks)
add_subdirectory(engine)
add_subdirectory(internal)
add_subdirectory(scratch)
add_subdirectory(audio)
38 changes: 38 additions & 0 deletions src/audio/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
option(LIBSCRATCHCPP_AUDIO_SUPPORT "Audio support" ON)

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

if (LIBSCRATCHCPP_AUDIO_SUPPORT)
add_library(miniaudio STATIC
${MINIAUDIO_SRC}/miniaudio.c
${MINIAUDIO_SRC}/miniaudio.h
)
target_include_directories(scratchcpp-audio PUBLIC ${CMAKE_CURRENT_LIST_DIR}/${MINIAUDIO_SRC})
target_link_libraries(scratchcpp-audio PRIVATE miniaudio)
target_compile_definitions(scratchcpp-audio PUBLIC LIBSCRATCHCPP_AUDIO_SUPPORT)
endif()

target_sources(scratchcpp-audio
PUBLIC
iaudioplayer.h
iaudioplayerfactory.h
audioplayerfactory.cpp
audioplayerfactory.h
)

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

#include <iostream>

#include "audioengine.h"

using namespace libscratchcpp;

AudioEngine AudioEngine::instance;

ma_engine *AudioEngine::engine()
{
return &instance.m_engine;
}

bool AudioEngine::initialized()
{
return instance.m_initialized;
}

AudioEngine::AudioEngine()
{
ma_result result;
result = ma_engine_init(NULL, &m_engine);

if (result != MA_SUCCESS) {
std::cerr << "Failed to initialize audio engine." << std::endl;
return;
}

m_initialized = true;
}

AudioEngine::~AudioEngine()
{
if (m_initialized)
ma_engine_uninit(&m_engine);
}
27 changes: 27 additions & 0 deletions src/audio/audioengine.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 <miniaudio.h>

namespace libscratchcpp
{

// This is a singleton which initializes and uninitializes the miniaudio engine
class AudioEngine
{
public:
static ma_engine *engine();
static bool initialized();

private:
AudioEngine();
~AudioEngine();

static AudioEngine instance;
ma_engine m_engine;
bool m_initialized = false;
};

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

#include <iostream>

#include "audioplayer.h"
#include "audioengine.h"

using namespace libscratchcpp;

AudioPlayer::AudioPlayer()
{
m_decoder = new ma_decoder;
m_sound = new ma_sound;
}

AudioPlayer::~AudioPlayer()
{
if (m_loaded) {
ma_sound_uninit(m_sound);
ma_decoder_uninit(m_decoder);
}

delete m_decoder;
delete m_sound;
}

bool AudioPlayer::load(unsigned int size, const void *data, unsigned long sampleRate)
{
if (!AudioEngine::initialized())
return false;

ma_engine *engine = AudioEngine::engine();

if (!data || size == 0)
return false;

ma_decoder_config config = ma_decoder_config_init(ma_format_f32, 2, sampleRate);
ma_result result = ma_decoder_init_memory(data, size, &config, m_decoder);

if (result != MA_SUCCESS) {
std::cerr << "Failed to decode sound." << std::endl;
return false;
}

ma_result initResult = ma_sound_init_from_data_source(engine, m_decoder, MA_SOUND_FLAG_DECODE, NULL, m_sound);

if (initResult != MA_SUCCESS) {
std::cerr << "Failed to init sound." << std::endl;
ma_decoder_uninit(m_decoder);
return false;
}

m_loaded = true;
return true;
}

void AudioPlayer::setVolume(float volume)
{
if (!AudioEngine::initialized())
return;

ma_sound_set_volume(m_sound, volume);
}

void AudioPlayer::start()
{
if (!AudioEngine::initialized())
return;

ma_result result = ma_sound_start(m_sound);

if (result != MA_SUCCESS) {
std::cerr << "Failed to start sound." << std::endl;
m_started = false;
} else
m_started = true;
}

void AudioPlayer::stop()
{
if (!AudioEngine::initialized())
return;

ma_result result = ma_sound_stop(m_sound);
m_started = false;

if (result != MA_SUCCESS)
std::cerr << "Failed to stop sound." << std::endl;
}

bool AudioPlayer::isPlaying() const
{
if (!AudioEngine::initialized())
return false;

return m_started && !m_sound->atEnd;
}
34 changes: 34 additions & 0 deletions src/audio/audioplayer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// SPDX-License-Identifier: Apache-2.0

#pragma once

#include "iaudioplayer.h"

struct ma_decoder;
struct ma_sound;

namespace libscratchcpp
{

class AudioPlayer : public IAudioPlayer
{
public:
AudioPlayer();
~AudioPlayer();

bool load(unsigned int size, const void *data, unsigned long sampleRate) override;
void setVolume(float volume) override;

void start() override;
void stop() override;

bool isPlaying() const override;

private:
ma_decoder *m_decoder = nullptr;
ma_sound *m_sound;
bool m_loaded = false;
bool m_started = false;
};

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

#include "audioplayerfactory.h"

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

using namespace libscratchcpp;

std::shared_ptr<AudioPlayerFactory> AudioPlayerFactory::m_instance = std::make_shared<AudioPlayerFactory>();

AudioPlayerFactory::AudioPlayerFactory()
{
}

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

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

#pragma once

#include "iaudioplayerfactory.h"

namespace libscratchcpp
{

class AudioPlayerFactory : public IAudioPlayerFactory
{
public:
AudioPlayerFactory();

static std::shared_ptr<AudioPlayerFactory> instance();
std::shared_ptr<IAudioPlayer> create() const override;

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

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

#include "audioplayerstub.h"

using namespace libscratchcpp;

AudioPlayerStub::AudioPlayerStub()
{
}

bool AudioPlayerStub::load(unsigned int size, const void *data, unsigned long sampleRate)
{
return true;
}

void AudioPlayerStub::setVolume(float volume)
{
}

void AudioPlayerStub::start()
{
}

void AudioPlayerStub::stop()
{
}

bool AudioPlayerStub::isPlaying() const
{
return false;
}
24 changes: 24 additions & 0 deletions src/audio/audioplayerstub.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// SPDX-License-Identifier: Apache-2.0

#pragma once

#include "iaudioplayer.h"

namespace libscratchcpp
{

class AudioPlayerStub : public IAudioPlayer
{
public:
AudioPlayerStub();

bool load(unsigned int size, const void *data, unsigned long sampleRate) override;
void setVolume(float volume) override;

void start() override;
void stop() override;

bool isPlaying() const override;
};

} // namespace libscratchcpp
Loading