33#include < scratchcpp/iengine.h>
44#include < scratchcpp/compiler.h>
55#include < scratchcpp/target.h>
6+ #include < scratchcpp/input.h>
7+ #include < scratchcpp/sound.h>
68
79#include " soundblocks.h"
810
@@ -16,14 +18,86 @@ std::string SoundBlocks::name() const
1618void SoundBlocks::registerBlocks (IEngine *engine)
1719{
1820 // Blocks
21+ engine->addCompileFunction (this , " sound_play" , &compilePlay);
22+ engine->addCompileFunction (this , " sound_playuntildone" , &compilePlayUntilDone);
23+ engine->addCompileFunction (this , " sound_stopallsounds" , &compileStopAllSounds);
1924 engine->addCompileFunction (this , " sound_changevolumeby" , &compileChangeVolumeBy);
2025 engine->addCompileFunction (this , " sound_setvolumeto" , &compileSetVolumeTo);
2126 engine->addCompileFunction (this , " sound_volume" , &compileVolume);
2227
2328 // Inputs
29+ engine->addInput (this , " SOUND_MENU" , SOUND_MENU);
2430 engine->addInput (this , " VOLUME" , VOLUME);
2531}
2632
33+ bool SoundBlocks::compilePlayCommon (Compiler *compiler, bool untilDone, bool *byIndex)
34+ {
35+ Target *target = compiler->target ();
36+ assert (target);
37+
38+ if (!target)
39+ return false ;
40+
41+ Input *input = compiler->input (SOUND_MENU);
42+
43+ if (input->type () != Input::Type::ObscuredShadow) {
44+ assert (input->pointsToDropdownMenu ());
45+ std::string value = input->selectedMenuItem ();
46+
47+ int index = target->findSound (value);
48+
49+ if (index == -1 ) {
50+ Value v (value);
51+
52+ if (v.type () == Value::Type::Integer) {
53+ compiler->addConstValue (v.toLong () - 1 );
54+ compiler->addFunctionCall (untilDone ? &playByIndexUntilDone : &playByIndex);
55+
56+ if (byIndex)
57+ *byIndex = true ;
58+
59+ return true ;
60+ }
61+ } else {
62+ compiler->addConstValue (index);
63+ compiler->addFunctionCall (untilDone ? &playByIndexUntilDone : &playByIndex);
64+
65+ if (byIndex)
66+ *byIndex = true ;
67+
68+ return true ;
69+ }
70+ } else {
71+ compiler->addInput (input);
72+ compiler->addFunctionCall (untilDone ? &playUntilDone : &play);
73+
74+ if (byIndex)
75+ *byIndex = false ;
76+
77+ return true ;
78+ }
79+
80+ return false ;
81+ }
82+
83+ void SoundBlocks::compilePlay (Compiler *compiler)
84+ {
85+ compilePlayCommon (compiler, false );
86+ }
87+
88+ void SoundBlocks::compilePlayUntilDone (Compiler *compiler)
89+ {
90+ bool byIndex = false ;
91+
92+ if (compilePlayCommon (compiler, true , &byIndex))
93+ compiler->addFunctionCall (byIndex ? &checkSoundByIndex : &checkSound);
94+ }
95+
96+ void SoundBlocks::compileStopAllSounds (Compiler *compiler)
97+ {
98+ compiler->addFunctionCall (&stopAllSounds);
99+ }
100+
27101void SoundBlocks::compileChangeVolumeBy (Compiler *compiler)
28102{
29103 compiler->addInput (VOLUME);
@@ -41,6 +115,161 @@ void SoundBlocks::compileVolume(Compiler *compiler)
41115 compiler->addFunctionCall (&volume);
42116}
43117
118+ Sound *SoundBlocks::getSoundByIndex (Target *target, long index)
119+ {
120+ long soundCount = target->sounds ().size ();
121+
122+ if (index < 0 || index >= soundCount) {
123+ if (index < 0 )
124+ index = std::fmod (soundCount + std::fmod (index, -soundCount), soundCount);
125+ else
126+ index = std::fmod (index, soundCount);
127+ }
128+
129+ return target->soundAt (index).get ();
130+ }
131+
132+ Sound *SoundBlocks::playCommon (VirtualMachine *vm)
133+ {
134+ Target *target = vm->target ();
135+ assert (target);
136+ const Value *name = vm->getInput (0 , 1 );
137+
138+ if (target) {
139+ Sound *sound = target->soundAt (target->findSound (name->toString ())).get ();
140+
141+ if (sound) {
142+ sound->start ();
143+ return sound;
144+ }
145+
146+ else if (name->type () == Value::Type::Integer) {
147+ sound = getSoundByIndex (target, name->toLong () - 1 );
148+
149+ if (sound) {
150+ sound->start ();
151+ return sound;
152+ }
153+ }
154+ }
155+
156+ return nullptr ;
157+ }
158+
159+ Sound *SoundBlocks::playByIndexCommon (VirtualMachine *vm)
160+ {
161+ Target *target = vm->target ();
162+ assert (target);
163+
164+ if (target) {
165+ Sound *sound = getSoundByIndex (target, vm->getInput (0 , 1 )->toInt ());
166+
167+ if (sound) {
168+ sound->start ();
169+ return sound;
170+ }
171+ }
172+
173+ return nullptr ;
174+ }
175+
176+ unsigned int SoundBlocks::play (VirtualMachine *vm)
177+ {
178+ Sound *sound = playCommon (vm);
179+
180+ if (sound)
181+ m_waitingSounds.erase (sound);
182+
183+ return 1 ;
184+ }
185+
186+ unsigned int SoundBlocks::playByIndex (VirtualMachine *vm)
187+ {
188+ Sound *sound = playByIndexCommon (vm);
189+
190+ if (sound)
191+ m_waitingSounds.erase (sound);
192+
193+ return 1 ;
194+ }
195+
196+ unsigned int SoundBlocks::playUntilDone (VirtualMachine *vm)
197+ {
198+ Sound *sound = playCommon (vm);
199+
200+ if (sound)
201+ m_waitingSounds[sound] = vm;
202+
203+ return 0 ; // leave the register for checkSound()
204+ }
205+
206+ unsigned int SoundBlocks::playByIndexUntilDone (VirtualMachine *vm)
207+ {
208+ Sound *sound = playByIndexCommon (vm);
209+
210+ if (sound)
211+ m_waitingSounds[sound] = vm;
212+
213+ return 0 ; // leave the register for checkSoundByIndex()
214+ }
215+
216+ unsigned int SoundBlocks::checkSound (VirtualMachine *vm)
217+ {
218+ Target *target = vm->target ();
219+ assert (target);
220+ const Value *name = vm->getInput (0 , 1 );
221+
222+ if (target) {
223+ Sound *sound = target->soundAt (target->findSound (name->toString ())).get ();
224+
225+ if (!sound && name->type () == Value::Type::Integer)
226+ sound = getSoundByIndex (target, name->toLong () - 1 );
227+
228+ if (sound) {
229+ auto it = m_waitingSounds.find (sound);
230+
231+ if (it != m_waitingSounds.cend () && it->second == vm) {
232+ if (sound->isPlaying ())
233+ vm->stop (true , true , true );
234+ else
235+ m_waitingSounds.erase (sound);
236+ }
237+ }
238+ }
239+
240+ return 1 ;
241+ }
242+
243+ unsigned int SoundBlocks::checkSoundByIndex (VirtualMachine *vm)
244+ {
245+ Target *target = vm->target ();
246+ assert (target);
247+
248+ if (target) {
249+ auto sound = getSoundByIndex (target, vm->getInput (0 , 1 )->toInt ());
250+
251+ if (sound) {
252+ auto it = m_waitingSounds.find (sound);
253+
254+ if (it != m_waitingSounds.cend () && it->second == vm) {
255+ if (sound->isPlaying ())
256+ vm->stop (true , true , true );
257+ else
258+ m_waitingSounds.erase (sound);
259+ }
260+ }
261+ }
262+
263+ return 1 ;
264+ }
265+
266+ unsigned int SoundBlocks::stopAllSounds (VirtualMachine *vm)
267+ {
268+ vm->engine ()->stopSounds ();
269+ m_waitingSounds.clear ();
270+ return 0 ;
271+ }
272+
44273unsigned int SoundBlocks::changeVolumeBy (VirtualMachine *vm)
45274{
46275 if (Target *target = vm->target ())
0 commit comments