Skip to content

Implement sound effects #569

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Aug 31, 2024
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ libscratchcpp::Project p("https://scratch.mit.edu/projects/XXXXXX");

- [x] Motion blocks
- [x] Looks blocks
- [ ] Sound blocks
- [x] Sound blocks
- [x] Event blocks
- [x] Control blocks
- [ ] Sensing blocks
Expand Down
9 changes: 8 additions & 1 deletion include/scratchcpp/sound.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ class SoundPrivate;
class LIBSCRATCHCPP_EXPORT Sound : public Asset
{
public:
enum class Effect
{
Pitch,
Pan
};

Sound(const std::string &name, const std::string &id, const std::string &format);
Sound(const Sound &) = delete;
virtual ~Sound() { }
Expand All @@ -27,11 +33,12 @@ class LIBSCRATCHCPP_EXPORT Sound : public Asset
void setSampleCount(int newSampleCount);

virtual void setVolume(double volume);
virtual void setEffect(Effect effect, double value);

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

virtual bool isPlaying();
virtual bool isPlaying() const;

Target *target() const;
void setTarget(Target *target);
Expand Down
6 changes: 6 additions & 0 deletions include/scratchcpp/target.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "global.h"
#include "spimpl.h"
#include "rect.h"
#include "sound.h"

namespace libscratchcpp
{
Expand Down Expand Up @@ -88,6 +89,11 @@ class LIBSCRATCHCPP_EXPORT Target
double volume() const;
void setVolume(double newVolume);

virtual double soundEffect(Sound::Effect effect) const;
virtual void setSoundEffect(Sound::Effect effect, double value);

virtual void clearSoundEffects();

virtual Rect boundingRect() const;
virtual Rect fastBoundingRect() const;

Expand Down
6 changes: 6 additions & 0 deletions src/audio/iaudioplayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ class IAudioPlayer
virtual float volume() const = 0;
virtual void setVolume(float volume) = 0;

virtual float pitch() const = 0;
virtual void setPitch(float pitch) = 0;

virtual float pan() const = 0;
virtual void setPan(float pan) = 0;

virtual bool isLoaded() const = 0;

virtual void start() = 0;
Expand Down
42 changes: 42 additions & 0 deletions src/audio/internal/audioplayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ bool AudioPlayer::load(unsigned int size, const void *data, unsigned long sample

m_loaded = true;
ma_sound_set_volume(m_sound, m_volume);
ma_sound_set_pitch(m_sound, m_pitch);
ma_sound_set_pan(m_sound, m_pan);
return true;
}

Expand All @@ -81,6 +83,8 @@ bool AudioPlayer::loadCopy(IAudioPlayer *player)
m_loaded = true;
m_copy = true;
ma_sound_set_volume(m_sound, m_volume);
ma_sound_set_pitch(m_sound, m_pitch);
ma_sound_set_pan(m_sound, m_pan);
return true;
}

Expand All @@ -99,6 +103,44 @@ void AudioPlayer::setVolume(float volume)
ma_sound_set_volume(m_sound, volume);
}

float AudioPlayer::pitch() const
{
return m_pitch;
}

void AudioPlayer::setPitch(float pitch)
{
/*
* 0.5 -> 220 Hz
* 1 -> 440 Hz
* 2 -> 880 Hz
* 4 -> 1760 Hz
* ...
*/
m_pitch = pitch;

if (!m_loaded)
return;

ma_sound_set_pitch(m_sound, pitch);
}

float AudioPlayer::pan() const
{
return m_pan;
}

void AudioPlayer::setPan(float pan)
{
// -1 ... 0 ... 1
m_pan = pan;

if (!m_loaded)
return;

ma_sound_set_pan(m_sound, pan);
}

bool AudioPlayer::isLoaded() const
{
return m_loaded;
Expand Down
8 changes: 8 additions & 0 deletions src/audio/internal/audioplayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ class AudioPlayer : public IAudioPlayer
float volume() const override;
void setVolume(float volume) override;

float pitch() const override;
void setPitch(float pitch) override;

float pan() const override;
void setPan(float pan) override;

bool isLoaded() const override;

void start() override;
Expand All @@ -36,6 +42,8 @@ class AudioPlayer : public IAudioPlayer
bool m_copy = false;
bool m_started = false;
float m_volume = 1;
float m_pitch = 1;
float m_pan = 0;
};

} // namespace libscratchcpp
20 changes: 20 additions & 0 deletions src/audio/internal/audioplayerstub.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,26 @@ void AudioPlayerStub::setVolume(float volume)
m_volume = volume;
}

float AudioPlayerStub::pitch() const
{
return m_pitch;
}

void AudioPlayerStub::setPitch(float pitch)
{
m_pitch = pitch;
}

float AudioPlayerStub::pan() const
{
return m_pan;
}

void AudioPlayerStub::setPan(float pan)
{
m_pan = pan;
}

bool AudioPlayerStub::isLoaded() const
{
return true;
Expand Down
8 changes: 8 additions & 0 deletions src/audio/internal/audioplayerstub.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ class AudioPlayerStub : public IAudioPlayer
float volume() const override;
void setVolume(float volume) override;

float pitch() const override;
void setPitch(float pitch) override;

float pan() const override;
void setPan(float pan) override;

bool isLoaded() const override;

void start() override;
Expand All @@ -27,6 +33,8 @@ class AudioPlayerStub : public IAudioPlayer

private:
float m_volume = 1;
float m_pitch = 1;
float m_pan = 0;
};

} // namespace libscratchcpp
97 changes: 97 additions & 0 deletions src/blocks/soundblocks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <scratchcpp/compiler.h>
#include <scratchcpp/target.h>
#include <scratchcpp/input.h>
#include <scratchcpp/field.h>
#include <scratchcpp/sound.h>

#include "soundblocks.h"
Expand Down Expand Up @@ -33,7 +34,10 @@ void SoundBlocks::registerBlocks(IEngine *engine)
engine->addCompileFunction(this, "sound_play", &compilePlay);
engine->addCompileFunction(this, "sound_playuntildone", &compilePlayUntilDone);
engine->addCompileFunction(this, "sound_stopallsounds", &compileStopAllSounds);
engine->addCompileFunction(this, "sound_seteffectto", &compileSetEffectTo);
engine->addCompileFunction(this, "sound_changeeffectby", &compileChangeEffectBy);
engine->addCompileFunction(this, "sound_changevolumeby", &compileChangeVolumeBy);
engine->addCompileFunction(this, "sound_cleareffects", &compileClearEffects);
engine->addCompileFunction(this, "sound_setvolumeto", &compileSetVolumeTo);
engine->addCompileFunction(this, "sound_volume", &compileVolume);

Expand All @@ -42,7 +46,15 @@ void SoundBlocks::registerBlocks(IEngine *engine)

// Inputs
engine->addInput(this, "SOUND_MENU", SOUND_MENU);
engine->addInput(this, "VALUE", VALUE);
engine->addInput(this, "VOLUME", VOLUME);

// Fields
engine->addField(this, "EFFECT", EFFECT);

// Field values
engine->addFieldValue(this, "PITCH", PITCH);
engine->addFieldValue(this, "PAN", PAN);
}

void SoundBlocks::onInit(IEngine *engine)
Expand Down Expand Up @@ -118,6 +130,51 @@ void SoundBlocks::compileStopAllSounds(Compiler *compiler)
compiler->addFunctionCall(&stopAllSounds);
}

void SoundBlocks::compileSetEffectTo(Compiler *compiler)
{
compiler->addInput(VALUE);
int option = compiler->field(EFFECT)->specialValueId();

switch (option) {
case PITCH:
compiler->addFunctionCall(&setPitchEffectTo);
break;

case PAN:
compiler->addFunctionCall(&setPanEffectTo);
break;

default:
assert(false);
break;
}
}

void SoundBlocks::compileChangeEffectBy(Compiler *compiler)
{
compiler->addInput(VALUE);
int option = compiler->field(EFFECT)->specialValueId();

switch (option) {
case PITCH:
compiler->addFunctionCall(&changePitchEffectBy);
break;

case PAN:
compiler->addFunctionCall(&changePanEffectBy);
break;

default:
assert(false);
break;
}
}

void SoundBlocks::compileClearEffects(Compiler *compiler)
{
compiler->addFunctionCall(&clearEffects);
}

void SoundBlocks::compileChangeVolumeBy(Compiler *compiler)
{
compiler->addInput(VOLUME);
Expand Down Expand Up @@ -296,6 +353,46 @@ unsigned int SoundBlocks::stopAllSounds(VirtualMachine *vm)
return 0;
}

unsigned int SoundBlocks::setPitchEffectTo(VirtualMachine *vm)
{
if (Target *target = vm->target())
target->setSoundEffect(Sound::Effect::Pitch, vm->getInput(0, 1)->toDouble());

return 1;
}

unsigned int SoundBlocks::setPanEffectTo(VirtualMachine *vm)
{
if (Target *target = vm->target())
target->setSoundEffect(Sound::Effect::Pan, vm->getInput(0, 1)->toDouble());

return 1;
}

unsigned int SoundBlocks::changePitchEffectBy(VirtualMachine *vm)
{
if (Target *target = vm->target())
target->setSoundEffect(Sound::Effect::Pitch, target->soundEffect(Sound::Effect::Pitch) + vm->getInput(0, 1)->toDouble());

return 1;
}

unsigned int SoundBlocks::changePanEffectBy(VirtualMachine *vm)
{
if (Target *target = vm->target())
target->setSoundEffect(Sound::Effect::Pan, target->soundEffect(Sound::Effect::Pan) + vm->getInput(0, 1)->toDouble());

return 1;
}

unsigned int SoundBlocks::clearEffects(VirtualMachine *vm)
{
if (Target *target = vm->target())
target->clearSoundEffects();

return 0;
}

unsigned int SoundBlocks::changeVolumeBy(VirtualMachine *vm)
{
if (Target *target = vm->target())
Expand Down
15 changes: 13 additions & 2 deletions src/blocks/soundblocks.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,19 @@ class SoundBlocks : public IBlockSection
enum Inputs
{
SOUND_MENU,
VALUE,
VOLUME
};

enum Fields
{

EFFECT
};

enum FieldValues
{

PITCH,
PAN
};

std::string name() const override;
Expand All @@ -42,6 +44,9 @@ class SoundBlocks : public IBlockSection
static void compilePlay(Compiler *compiler);
static void compilePlayUntilDone(Compiler *compiler);
static void compileStopAllSounds(Compiler *compiler);
static void compileSetEffectTo(Compiler *compiler);
static void compileChangeEffectBy(Compiler *compiler);
static void compileClearEffects(Compiler *compiler);
static void compileChangeVolumeBy(Compiler *compiler);
static void compileSetVolumeTo(Compiler *compiler);
static void compileVolume(Compiler *compiler);
Expand All @@ -62,6 +67,12 @@ class SoundBlocks : public IBlockSection

static unsigned int stopAllSounds(VirtualMachine *vm);

static unsigned int setPitchEffectTo(VirtualMachine *vm);
static unsigned int setPanEffectTo(VirtualMachine *vm);
static unsigned int changePitchEffectBy(VirtualMachine *vm);
static unsigned int changePanEffectBy(VirtualMachine *vm);
static unsigned int clearEffects(VirtualMachine *vm);

static unsigned int changeVolumeBy(VirtualMachine *vm);
static unsigned int setVolumeTo(VirtualMachine *vm);
static unsigned int volume(VirtualMachine *vm);
Expand Down
Loading
Loading