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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ libscratchcpp::Project p("https://scratch.mit.edu/projects/XXXXXX");
- [x] Motion blocks
- [x] Looks blocks
- [ ] Sound blocks
- [ ] Event blocks
- [x] Event blocks
- [x] Control blocks
- [ ] Sensing blocks
- [x] Operator blocks
Expand Down
3 changes: 3 additions & 0 deletions include/scratchcpp/block.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ class LIBSCRATCHCPP_EXPORT Block : public Entity
BlockComp compileFunction() const;
void setCompileFunction(BlockComp newCompileFunction);

BlockComp hatPredicateCompileFunction() const;
void setHatPredicateCompileFunction(HatPredicateCompileFunc newHatPredicateCompileFunction);

bool mutationHasNext() const;
void setMutationHasNext(bool newMutationHasNext);

Expand Down
1 change: 1 addition & 0 deletions include/scratchcpp/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class LIBSCRATCHCPP_EXPORT Compiler
void end();

const std::vector<unsigned int> &bytecode() const;
const std::vector<unsigned int> &hatPredicateBytecode() const;

IEngine *engine() const;
Target *target() const;
Expand Down
7 changes: 7 additions & 0 deletions include/scratchcpp/global.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,13 @@ using MonitorNameFunc = const std::string &(*)(Block *);
*/
using MonitorChangeFunc = void (*)(Block *, const Value &newValue);

/*!
* \typedef HatPredicateCompileFunc
*
* HatPredicateCompileFunc is a function pointer for functions which are used to compile edge-activated hat predicates to bytecode.
*/
using HatPredicateCompileFunc = void (*)(Compiler *vm);

} // namespace libscratchcpp

#endif // LIBSCRATCHCPP_GLOBAL_H
10 changes: 10 additions & 0 deletions include/scratchcpp/iengine.h
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,13 @@ class LIBSCRATCHCPP_EXPORT IEngine
*/
virtual void addCompileFunction(IBlockSection *section, const std::string &opcode, BlockComp f) = 0;

/*!
* Call this from IBlockSection#registerBlocks() to add a hat block predicate compile function to a block section.
* \note This only works with edge-activated hats.
* \see <a href="blockSections.html">Block sections</a>
*/
virtual void addHatPredicateCompileFunction(IBlockSection *section, const std::string &opcode, HatPredicateCompileFunc f) = 0;

/*!
* Call this from IBlockSection#registerBlocks() to add a monitor name function to a block section.
* \see <a href="blockSections.html">Block sections</a>
Expand Down Expand Up @@ -292,6 +299,9 @@ class LIBSCRATCHCPP_EXPORT IEngine
/* Registers the given "when this sprite/stage clicked" script. */
virtual void addTargetClickScript(std::shared_ptr<Block> hatBlock) = 0;

/* Registers the given "when greater than" script. */
virtual void addWhenGreaterThanScript(std::shared_ptr<Block> hatBlock) = 0;

/*! Returns the list of targets. */
virtual const std::vector<std::shared_ptr<Target>> &targets() const = 0;

Expand Down
3 changes: 3 additions & 0 deletions include/scratchcpp/script.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ class LIBSCRATCHCPP_EXPORT Script
const std::vector<unsigned int> &bytecodeVector() const;
void setBytecode(const std::vector<unsigned int> &code);

void setHatPredicateBytecode(const std::vector<unsigned int> &code);
bool runHatPredicate();

void setProcedures(const std::vector<unsigned int *> &procedures);
void setFunctions(const std::vector<BlockFunc> &functions);
void setConstValues(const std::vector<Value> &values);
Expand Down
66 changes: 66 additions & 0 deletions src/blocks/eventblocks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,17 @@
#include <scratchcpp/field.h>
#include <scratchcpp/stage.h>
#include <scratchcpp/costume.h>
#include <scratchcpp/block.h>
#include <scratchcpp/itimer.h>

#include "eventblocks.h"
#include "audio/audioinput.h"
#include "audio/iaudioloudness.h"

using namespace libscratchcpp;

IAudioInput *EventBlocks::audioInput = nullptr;

std::string EventBlocks::name() const
{
return "Events";
Expand All @@ -28,15 +34,25 @@ void EventBlocks::registerBlocks(IEngine *engine)
engine->addCompileFunction(this, "event_broadcastandwait", &compileBroadcastAndWait);
engine->addCompileFunction(this, "event_whenbroadcastreceived", &compileWhenBroadcastReceived);
engine->addCompileFunction(this, "event_whenbackdropswitchesto", &compileWhenBackdropSwitchesTo);
engine->addCompileFunction(this, "event_whengreaterthan", &compileWhenGreaterThan);
engine->addCompileFunction(this, "event_whenkeypressed", &compileWhenKeyPressed);

// Hat predicates
engine->addHatPredicateCompileFunction(this, "event_whengreaterthan", &compileWhenGreaterThanPredicate);

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

// Fields
engine->addField(this, "BROADCAST_OPTION", BROADCAST_OPTION);
engine->addField(this, "BACKDROP", BACKDROP);
engine->addField(this, "WHENGREATERTHANMENU", WHENGREATERTHANMENU);
engine->addField(this, "KEY_OPTION", KEY_OPTION);

// Fields values
engine->addFieldValue(this, "LOUDNESS", Loudness);
engine->addFieldValue(this, "TIMER", Timer);
}

void EventBlocks::compileWhenFlagClicked(Compiler *compiler)
Expand Down Expand Up @@ -97,6 +113,38 @@ void EventBlocks::compileWhenBackdropSwitchesTo(Compiler *compiler)
compiler->engine()->addBackdropChangeScript(compiler->block(), BACKDROP);
}

void EventBlocks::compileWhenGreaterThanPredicate(Compiler *compiler)
{
Field *field = compiler->field(WHENGREATERTHANMENU);
BlockFunc predicate = nullptr;

if (field) {
switch (field->specialValueId()) {
case Loudness:
predicate = &whenLoudnessGreaterThanPredicate;
break;

case Timer:
predicate = &whenTimerGreaterThanPredicate;
break;

default:
compiler->addInstruction(vm::OP_NULL);
return;
}
}

if (predicate) {
compiler->addInput(VALUE);
compiler->addFunctionCall(predicate);
}
}

void EventBlocks::compileWhenGreaterThan(Compiler *compiler)
{
compiler->engine()->addWhenGreaterThanScript(compiler->block());
}

void EventBlocks::compileWhenKeyPressed(Compiler *compiler)
{
// NOTE: Field values don't have to be registered because keys are referenced by their names
Expand Down Expand Up @@ -140,3 +188,21 @@ unsigned int EventBlocks::checkBroadcastByIndex(VirtualMachine *vm)
vm->stop(true, true, true);
return 1;
}

unsigned int EventBlocks::whenLoudnessGreaterThanPredicate(VirtualMachine *vm)
{
if (!audioInput)
audioInput = AudioInput::instance().get();

auto audioLoudness = audioInput->audioLoudness();
const Value &operand = *vm->getInput(0, 1);
vm->replaceReturnValue(Value(audioLoudness->getLoudness()) > operand, 1);
return 0;
}

unsigned int EventBlocks::whenTimerGreaterThanPredicate(VirtualMachine *vm)
{
const Value &operand = *vm->getInput(0, 1);
vm->replaceReturnValue(Value(vm->engine()->timer()->value()) > operand, 1);
return 0;
}
18 changes: 17 additions & 1 deletion src/blocks/eventblocks.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,32 @@ namespace libscratchcpp

class Compiler;
class VirtualMachine;
class IAudioInput;

/*! \brief The EventBlocks class contains the implementation of event blocks. */
class EventBlocks : public IBlockSection
{
public:
enum Inputs
{
BROADCAST_INPUT
BROADCAST_INPUT,
VALUE
};

enum Fields
{
BROADCAST_OPTION,
BACKDROP,
WHENGREATERTHANMENU,
KEY_OPTION
};

enum FieldValues
{
Loudness,
Timer
};

std::string name() const override;

void registerBlocks(IEngine *engine) override;
Expand All @@ -37,6 +46,8 @@ class EventBlocks : public IBlockSection
static void compileBroadcastAndWait(Compiler *compiler);
static void compileWhenBroadcastReceived(Compiler *compiler);
static void compileWhenBackdropSwitchesTo(Compiler *compiler);
static void compileWhenGreaterThanPredicate(Compiler *compiler);
static void compileWhenGreaterThan(Compiler *compiler);
static void compileWhenKeyPressed(Compiler *compiler);

static unsigned int broadcast(VirtualMachine *vm);
Expand All @@ -45,6 +56,11 @@ class EventBlocks : public IBlockSection
static unsigned int broadcastByIndexAndWait(VirtualMachine *vm);
static unsigned int checkBroadcast(VirtualMachine *vm);
static unsigned int checkBroadcastByIndex(VirtualMachine *vm);

static unsigned int whenLoudnessGreaterThanPredicate(VirtualMachine *vm);
static unsigned int whenTimerGreaterThanPredicate(VirtualMachine *vm);

static IAudioInput *audioInput;
};

} // namespace libscratchcpp
42 changes: 42 additions & 0 deletions src/blocks/sensingblocks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@
#include "sensingblocks.h"

#include "../engine/internal/clock.h"
#include "audio/audioinput.h"
#include "audio/iaudioloudness.h"

using namespace libscratchcpp;

IClock *SensingBlocks::clock = nullptr;
IAudioInput *SensingBlocks::audioInput = nullptr;

std::string SensingBlocks::name() const
{
Expand All @@ -35,6 +38,8 @@ void SensingBlocks::registerBlocks(IEngine *engine)
engine->addCompileFunction(this, "sensing_mousex", &compileMouseX);
engine->addCompileFunction(this, "sensing_mousey", &compileMouseY);
engine->addCompileFunction(this, "sensing_setdragmode", &compileSetDragMode);
engine->addCompileFunction(this, "sensing_loudness", &compileLoudness);
engine->addCompileFunction(this, "sensing_loud", &compileLoud);
engine->addCompileFunction(this, "sensing_timer", &compileTimer);
engine->addCompileFunction(this, "sensing_resettimer", &compileResetTimer);
engine->addCompileFunction(this, "sensing_of", &compileOf);
Expand All @@ -45,6 +50,7 @@ void SensingBlocks::registerBlocks(IEngine *engine)
engine->addMonitorNameFunction(this, "sensing_mousedown", &mouseDownMonitorName);
engine->addMonitorNameFunction(this, "sensing_mousex", &mouseXMonitorName);
engine->addMonitorNameFunction(this, "sensing_mousey", &mouseYMonitorName);
engine->addMonitorNameFunction(this, "sensing_loudness", &loudnessMonitorName);
engine->addMonitorNameFunction(this, "sensing_timer", &timerMonitorName);
engine->addMonitorNameFunction(this, "sensing_current", &currentMonitorName);
engine->addMonitorNameFunction(this, "sensing_dayssince2000", &daysSince2000MonitorName);
Expand Down Expand Up @@ -156,6 +162,16 @@ void SensingBlocks::compileSetDragMode(Compiler *compiler)
}
}

void SensingBlocks::compileLoudness(Compiler *compiler)
{
compiler->addFunctionCall(&loudness);
}

void SensingBlocks::compileLoud(Compiler *compiler)
{
compiler->addFunctionCall(&loud);
}

void SensingBlocks::compileTimer(Compiler *compiler)
{
compiler->addFunctionCall(&timer);
Expand Down Expand Up @@ -354,6 +370,12 @@ const std::string &SensingBlocks::mouseYMonitorName(Block *block)
return name;
}

const std::string &SensingBlocks::loudnessMonitorName(Block *block)
{
static const std::string name = "loudness";
return name;
}

const std::string &SensingBlocks::timerMonitorName(Block *block)
{
static const std::string name = "timer";
Expand Down Expand Up @@ -453,6 +475,26 @@ unsigned int SensingBlocks::setNotDraggableMode(VirtualMachine *vm)
return 0;
}

unsigned int SensingBlocks::loudness(VirtualMachine *vm)
{
if (!audioInput)
audioInput = AudioInput::instance().get();

auto audioLoudness = audioInput->audioLoudness();
vm->addReturnValue(audioLoudness->getLoudness());
return 0;
}

unsigned int SensingBlocks::loud(VirtualMachine *vm)
{
if (!audioInput)
audioInput = AudioInput::instance().get();

auto audioLoudness = audioInput->audioLoudness();
vm->addReturnValue(audioLoudness->getLoudness() > 10.0);
return 0;
}

unsigned int SensingBlocks::distanceTo(VirtualMachine *vm)
{
Sprite *sprite = dynamic_cast<Sprite *>(vm->target());
Expand Down
8 changes: 8 additions & 0 deletions src/blocks/sensingblocks.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ namespace libscratchcpp
{

class Target;
class IAudioInput;

/*! \brief The SensingBlocks class contains the implementation of sensing blocks. */
class SensingBlocks : public IBlockSection
Expand Down Expand Up @@ -66,6 +67,8 @@ class SensingBlocks : public IBlockSection
static void compileMouseX(Compiler *compiler);
static void compileMouseY(Compiler *compiler);
static void compileSetDragMode(Compiler *compiler);
static void compileLoudness(Compiler *compiler);
static void compileLoud(Compiler *compiler);
static void compileTimer(Compiler *compiler);
static void compileResetTimer(Compiler *compiler);
static void compileOf(Compiler *compiler);
Expand All @@ -75,6 +78,7 @@ class SensingBlocks : public IBlockSection
static const std::string &mouseDownMonitorName(Block *block);
static const std::string &mouseXMonitorName(Block *block);
static const std::string &mouseYMonitorName(Block *block);
static const std::string &loudnessMonitorName(Block *block);
static const std::string &timerMonitorName(Block *block);
static const std::string &currentMonitorName(Block *block);
static const std::string &daysSince2000MonitorName(Block *block);
Expand All @@ -87,6 +91,9 @@ class SensingBlocks : public IBlockSection
static unsigned int setDraggableMode(VirtualMachine *vm);
static unsigned int setNotDraggableMode(VirtualMachine *vm);

static unsigned int loudness(VirtualMachine *vm);
static unsigned int loud(VirtualMachine *vm);

static unsigned int distanceTo(VirtualMachine *vm);
static unsigned int distanceToByIndex(VirtualMachine *vm);
static unsigned int distanceToMousePointer(VirtualMachine *vm);
Expand Down Expand Up @@ -128,6 +135,7 @@ class SensingBlocks : public IBlockSection
static unsigned int daysSince2000(VirtualMachine *vm);

static IClock *clock;
static IAudioInput *audioInput;

private:
struct Question
Expand Down
Loading