Skip to content

Commit 279cd24

Browse files
authored
Merge pull request #512 from scratchcpp/audio_input_blocks
Implement audio input blocks
2 parents 27b1734 + 20adf83 commit 279cd24

30 files changed

+779
-16
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ libscratchcpp::Project p("https://scratch.mit.edu/projects/XXXXXX");
125125
- [x] Motion blocks
126126
- [x] Looks blocks
127127
- [ ] Sound blocks
128-
- [ ] Event blocks
128+
- [x] Event blocks
129129
- [x] Control blocks
130130
- [ ] Sensing blocks
131131
- [x] Operator blocks

include/scratchcpp/block.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ class LIBSCRATCHCPP_EXPORT Block : public Entity
7070
BlockComp compileFunction() const;
7171
void setCompileFunction(BlockComp newCompileFunction);
7272

73+
BlockComp hatPredicateCompileFunction() const;
74+
void setHatPredicateCompileFunction(HatPredicateCompileFunc newHatPredicateCompileFunction);
75+
7376
bool mutationHasNext() const;
7477
void setMutationHasNext(bool newMutationHasNext);
7578

include/scratchcpp/compiler.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class LIBSCRATCHCPP_EXPORT Compiler
4242
void end();
4343

4444
const std::vector<unsigned int> &bytecode() const;
45+
const std::vector<unsigned int> &hatPredicateBytecode() const;
4546

4647
IEngine *engine() const;
4748
Target *target() const;

include/scratchcpp/global.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,13 @@ using MonitorNameFunc = const std::string &(*)(Block *);
6262
*/
6363
using MonitorChangeFunc = void (*)(Block *, const Value &newValue);
6464

65+
/*!
66+
* \typedef HatPredicateCompileFunc
67+
*
68+
* HatPredicateCompileFunc is a function pointer for functions which are used to compile edge-activated hat predicates to bytecode.
69+
*/
70+
using HatPredicateCompileFunc = void (*)(Compiler *vm);
71+
6572
} // namespace libscratchcpp
6673

6774
#endif // LIBSCRATCHCPP_GLOBAL_H

include/scratchcpp/iengine.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,13 @@ class LIBSCRATCHCPP_EXPORT IEngine
223223
*/
224224
virtual void addCompileFunction(IBlockSection *section, const std::string &opcode, BlockComp f) = 0;
225225

226+
/*!
227+
* Call this from IBlockSection#registerBlocks() to add a hat block predicate compile function to a block section.
228+
* \note This only works with edge-activated hats.
229+
* \see <a href="blockSections.html">Block sections</a>
230+
*/
231+
virtual void addHatPredicateCompileFunction(IBlockSection *section, const std::string &opcode, HatPredicateCompileFunc f) = 0;
232+
226233
/*!
227234
* Call this from IBlockSection#registerBlocks() to add a monitor name function to a block section.
228235
* \see <a href="blockSections.html">Block sections</a>
@@ -292,6 +299,9 @@ class LIBSCRATCHCPP_EXPORT IEngine
292299
/* Registers the given "when this sprite/stage clicked" script. */
293300
virtual void addTargetClickScript(std::shared_ptr<Block> hatBlock) = 0;
294301

302+
/* Registers the given "when greater than" script. */
303+
virtual void addWhenGreaterThanScript(std::shared_ptr<Block> hatBlock) = 0;
304+
295305
/*! Returns the list of targets. */
296306
virtual const std::vector<std::shared_ptr<Target>> &targets() const = 0;
297307

include/scratchcpp/script.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ class LIBSCRATCHCPP_EXPORT Script
3434
const std::vector<unsigned int> &bytecodeVector() const;
3535
void setBytecode(const std::vector<unsigned int> &code);
3636

37+
void setHatPredicateBytecode(const std::vector<unsigned int> &code);
38+
bool runHatPredicate();
39+
3740
void setProcedures(const std::vector<unsigned int *> &procedures);
3841
void setFunctions(const std::vector<BlockFunc> &functions);
3942
void setConstValues(const std::vector<Value> &values);

src/blocks/eventblocks.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,17 @@
88
#include <scratchcpp/field.h>
99
#include <scratchcpp/stage.h>
1010
#include <scratchcpp/costume.h>
11+
#include <scratchcpp/block.h>
12+
#include <scratchcpp/itimer.h>
1113

1214
#include "eventblocks.h"
15+
#include "audio/audioinput.h"
16+
#include "audio/iaudioloudness.h"
1317

1418
using namespace libscratchcpp;
1519

20+
IAudioInput *EventBlocks::audioInput = nullptr;
21+
1622
std::string EventBlocks::name() const
1723
{
1824
return "Events";
@@ -28,15 +34,25 @@ void EventBlocks::registerBlocks(IEngine *engine)
2834
engine->addCompileFunction(this, "event_broadcastandwait", &compileBroadcastAndWait);
2935
engine->addCompileFunction(this, "event_whenbroadcastreceived", &compileWhenBroadcastReceived);
3036
engine->addCompileFunction(this, "event_whenbackdropswitchesto", &compileWhenBackdropSwitchesTo);
37+
engine->addCompileFunction(this, "event_whengreaterthan", &compileWhenGreaterThan);
3138
engine->addCompileFunction(this, "event_whenkeypressed", &compileWhenKeyPressed);
3239

40+
// Hat predicates
41+
engine->addHatPredicateCompileFunction(this, "event_whengreaterthan", &compileWhenGreaterThanPredicate);
42+
3343
// Inputs
3444
engine->addInput(this, "BROADCAST_INPUT", BROADCAST_INPUT);
45+
engine->addInput(this, "VALUE", VALUE);
3546

3647
// Fields
3748
engine->addField(this, "BROADCAST_OPTION", BROADCAST_OPTION);
3849
engine->addField(this, "BACKDROP", BACKDROP);
50+
engine->addField(this, "WHENGREATERTHANMENU", WHENGREATERTHANMENU);
3951
engine->addField(this, "KEY_OPTION", KEY_OPTION);
52+
53+
// Fields values
54+
engine->addFieldValue(this, "LOUDNESS", Loudness);
55+
engine->addFieldValue(this, "TIMER", Timer);
4056
}
4157

4258
void EventBlocks::compileWhenFlagClicked(Compiler *compiler)
@@ -97,6 +113,38 @@ void EventBlocks::compileWhenBackdropSwitchesTo(Compiler *compiler)
97113
compiler->engine()->addBackdropChangeScript(compiler->block(), BACKDROP);
98114
}
99115

116+
void EventBlocks::compileWhenGreaterThanPredicate(Compiler *compiler)
117+
{
118+
Field *field = compiler->field(WHENGREATERTHANMENU);
119+
BlockFunc predicate = nullptr;
120+
121+
if (field) {
122+
switch (field->specialValueId()) {
123+
case Loudness:
124+
predicate = &whenLoudnessGreaterThanPredicate;
125+
break;
126+
127+
case Timer:
128+
predicate = &whenTimerGreaterThanPredicate;
129+
break;
130+
131+
default:
132+
compiler->addInstruction(vm::OP_NULL);
133+
return;
134+
}
135+
}
136+
137+
if (predicate) {
138+
compiler->addInput(VALUE);
139+
compiler->addFunctionCall(predicate);
140+
}
141+
}
142+
143+
void EventBlocks::compileWhenGreaterThan(Compiler *compiler)
144+
{
145+
compiler->engine()->addWhenGreaterThanScript(compiler->block());
146+
}
147+
100148
void EventBlocks::compileWhenKeyPressed(Compiler *compiler)
101149
{
102150
// NOTE: Field values don't have to be registered because keys are referenced by their names
@@ -140,3 +188,21 @@ unsigned int EventBlocks::checkBroadcastByIndex(VirtualMachine *vm)
140188
vm->stop(true, true, true);
141189
return 1;
142190
}
191+
192+
unsigned int EventBlocks::whenLoudnessGreaterThanPredicate(VirtualMachine *vm)
193+
{
194+
if (!audioInput)
195+
audioInput = AudioInput::instance().get();
196+
197+
auto audioLoudness = audioInput->audioLoudness();
198+
const Value &operand = *vm->getInput(0, 1);
199+
vm->replaceReturnValue(Value(audioLoudness->getLoudness()) > operand, 1);
200+
return 0;
201+
}
202+
203+
unsigned int EventBlocks::whenTimerGreaterThanPredicate(VirtualMachine *vm)
204+
{
205+
const Value &operand = *vm->getInput(0, 1);
206+
vm->replaceReturnValue(Value(vm->engine()->timer()->value()) > operand, 1);
207+
return 0;
208+
}

src/blocks/eventblocks.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,32 @@ namespace libscratchcpp
99

1010
class Compiler;
1111
class VirtualMachine;
12+
class IAudioInput;
1213

1314
/*! \brief The EventBlocks class contains the implementation of event blocks. */
1415
class EventBlocks : public IBlockSection
1516
{
1617
public:
1718
enum Inputs
1819
{
19-
BROADCAST_INPUT
20+
BROADCAST_INPUT,
21+
VALUE
2022
};
2123

2224
enum Fields
2325
{
2426
BROADCAST_OPTION,
2527
BACKDROP,
28+
WHENGREATERTHANMENU,
2629
KEY_OPTION
2730
};
2831

32+
enum FieldValues
33+
{
34+
Loudness,
35+
Timer
36+
};
37+
2938
std::string name() const override;
3039

3140
void registerBlocks(IEngine *engine) override;
@@ -37,6 +46,8 @@ class EventBlocks : public IBlockSection
3746
static void compileBroadcastAndWait(Compiler *compiler);
3847
static void compileWhenBroadcastReceived(Compiler *compiler);
3948
static void compileWhenBackdropSwitchesTo(Compiler *compiler);
49+
static void compileWhenGreaterThanPredicate(Compiler *compiler);
50+
static void compileWhenGreaterThan(Compiler *compiler);
4051
static void compileWhenKeyPressed(Compiler *compiler);
4152

4253
static unsigned int broadcast(VirtualMachine *vm);
@@ -45,6 +56,11 @@ class EventBlocks : public IBlockSection
4556
static unsigned int broadcastByIndexAndWait(VirtualMachine *vm);
4657
static unsigned int checkBroadcast(VirtualMachine *vm);
4758
static unsigned int checkBroadcastByIndex(VirtualMachine *vm);
59+
60+
static unsigned int whenLoudnessGreaterThanPredicate(VirtualMachine *vm);
61+
static unsigned int whenTimerGreaterThanPredicate(VirtualMachine *vm);
62+
63+
static IAudioInput *audioInput;
4864
};
4965

5066
} // namespace libscratchcpp

src/blocks/sensingblocks.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,13 @@
1414
#include "sensingblocks.h"
1515

1616
#include "../engine/internal/clock.h"
17+
#include "audio/audioinput.h"
18+
#include "audio/iaudioloudness.h"
1719

1820
using namespace libscratchcpp;
1921

2022
IClock *SensingBlocks::clock = nullptr;
23+
IAudioInput *SensingBlocks::audioInput = nullptr;
2124

2225
std::string SensingBlocks::name() const
2326
{
@@ -35,6 +38,8 @@ void SensingBlocks::registerBlocks(IEngine *engine)
3538
engine->addCompileFunction(this, "sensing_mousex", &compileMouseX);
3639
engine->addCompileFunction(this, "sensing_mousey", &compileMouseY);
3740
engine->addCompileFunction(this, "sensing_setdragmode", &compileSetDragMode);
41+
engine->addCompileFunction(this, "sensing_loudness", &compileLoudness);
42+
engine->addCompileFunction(this, "sensing_loud", &compileLoud);
3843
engine->addCompileFunction(this, "sensing_timer", &compileTimer);
3944
engine->addCompileFunction(this, "sensing_resettimer", &compileResetTimer);
4045
engine->addCompileFunction(this, "sensing_of", &compileOf);
@@ -45,6 +50,7 @@ void SensingBlocks::registerBlocks(IEngine *engine)
4550
engine->addMonitorNameFunction(this, "sensing_mousedown", &mouseDownMonitorName);
4651
engine->addMonitorNameFunction(this, "sensing_mousex", &mouseXMonitorName);
4752
engine->addMonitorNameFunction(this, "sensing_mousey", &mouseYMonitorName);
53+
engine->addMonitorNameFunction(this, "sensing_loudness", &loudnessMonitorName);
4854
engine->addMonitorNameFunction(this, "sensing_timer", &timerMonitorName);
4955
engine->addMonitorNameFunction(this, "sensing_current", &currentMonitorName);
5056
engine->addMonitorNameFunction(this, "sensing_dayssince2000", &daysSince2000MonitorName);
@@ -156,6 +162,16 @@ void SensingBlocks::compileSetDragMode(Compiler *compiler)
156162
}
157163
}
158164

165+
void SensingBlocks::compileLoudness(Compiler *compiler)
166+
{
167+
compiler->addFunctionCall(&loudness);
168+
}
169+
170+
void SensingBlocks::compileLoud(Compiler *compiler)
171+
{
172+
compiler->addFunctionCall(&loud);
173+
}
174+
159175
void SensingBlocks::compileTimer(Compiler *compiler)
160176
{
161177
compiler->addFunctionCall(&timer);
@@ -354,6 +370,12 @@ const std::string &SensingBlocks::mouseYMonitorName(Block *block)
354370
return name;
355371
}
356372

373+
const std::string &SensingBlocks::loudnessMonitorName(Block *block)
374+
{
375+
static const std::string name = "loudness";
376+
return name;
377+
}
378+
357379
const std::string &SensingBlocks::timerMonitorName(Block *block)
358380
{
359381
static const std::string name = "timer";
@@ -453,6 +475,26 @@ unsigned int SensingBlocks::setNotDraggableMode(VirtualMachine *vm)
453475
return 0;
454476
}
455477

478+
unsigned int SensingBlocks::loudness(VirtualMachine *vm)
479+
{
480+
if (!audioInput)
481+
audioInput = AudioInput::instance().get();
482+
483+
auto audioLoudness = audioInput->audioLoudness();
484+
vm->addReturnValue(audioLoudness->getLoudness());
485+
return 0;
486+
}
487+
488+
unsigned int SensingBlocks::loud(VirtualMachine *vm)
489+
{
490+
if (!audioInput)
491+
audioInput = AudioInput::instance().get();
492+
493+
auto audioLoudness = audioInput->audioLoudness();
494+
vm->addReturnValue(audioLoudness->getLoudness() > 10.0);
495+
return 0;
496+
}
497+
456498
unsigned int SensingBlocks::distanceTo(VirtualMachine *vm)
457499
{
458500
Sprite *sprite = dynamic_cast<Sprite *>(vm->target());

src/blocks/sensingblocks.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ namespace libscratchcpp
1212
{
1313

1414
class Target;
15+
class IAudioInput;
1516

1617
/*! \brief The SensingBlocks class contains the implementation of sensing blocks. */
1718
class SensingBlocks : public IBlockSection
@@ -66,6 +67,8 @@ class SensingBlocks : public IBlockSection
6667
static void compileMouseX(Compiler *compiler);
6768
static void compileMouseY(Compiler *compiler);
6869
static void compileSetDragMode(Compiler *compiler);
70+
static void compileLoudness(Compiler *compiler);
71+
static void compileLoud(Compiler *compiler);
6972
static void compileTimer(Compiler *compiler);
7073
static void compileResetTimer(Compiler *compiler);
7174
static void compileOf(Compiler *compiler);
@@ -75,6 +78,7 @@ class SensingBlocks : public IBlockSection
7578
static const std::string &mouseDownMonitorName(Block *block);
7679
static const std::string &mouseXMonitorName(Block *block);
7780
static const std::string &mouseYMonitorName(Block *block);
81+
static const std::string &loudnessMonitorName(Block *block);
7882
static const std::string &timerMonitorName(Block *block);
7983
static const std::string &currentMonitorName(Block *block);
8084
static const std::string &daysSince2000MonitorName(Block *block);
@@ -87,6 +91,9 @@ class SensingBlocks : public IBlockSection
8791
static unsigned int setDraggableMode(VirtualMachine *vm);
8892
static unsigned int setNotDraggableMode(VirtualMachine *vm);
8993

94+
static unsigned int loudness(VirtualMachine *vm);
95+
static unsigned int loud(VirtualMachine *vm);
96+
9097
static unsigned int distanceTo(VirtualMachine *vm);
9198
static unsigned int distanceToByIndex(VirtualMachine *vm);
9299
static unsigned int distanceToMousePointer(VirtualMachine *vm);
@@ -128,6 +135,7 @@ class SensingBlocks : public IBlockSection
128135
static unsigned int daysSince2000(VirtualMachine *vm);
129136

130137
static IClock *clock;
138+
static IAudioInput *audioInput;
131139

132140
private:
133141
struct Question

0 commit comments

Comments
 (0)