Skip to content

Commit 4ec3f1f

Browse files
committed
fix #538: Fix sound clones not stopping
1 parent 8836ab1 commit 4ec3f1f

File tree

6 files changed

+92
-22
lines changed

6 files changed

+92
-22
lines changed

include/scratchcpp/sound.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ class LIBSCRATCHCPP_EXPORT Sound : public Asset
4242
void processData(unsigned int size, void *data) override;
4343

4444
private:
45+
void stopCloneSounds();
46+
4547
spimpl::unique_impl_ptr<SoundPrivate> impl;
4648
};
4749

src/engine/internal/engine.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -459,14 +459,11 @@ void Engine::deinitClone(std::shared_ptr<Sprite> clone)
459459

460460
void Engine::stopSounds()
461461
{
462-
// TODO: Loop through clones
463462
for (auto target : m_targets) {
464463
const auto &sounds = target->sounds();
465464

466-
for (auto sound : sounds) {
467-
if (sound->isPlaying())
468-
sound->stop();
469-
}
465+
for (auto sound : sounds)
466+
sound->stop();
470467
}
471468
}
472469

src/scratch/sound.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// SPDX-License-Identifier: Apache-2.0
22

33
#include <scratchcpp/sound.h>
4+
#include <scratchcpp/sprite.h>
45
#include <iostream>
56

67
#include "sound_p.h"
@@ -47,12 +48,16 @@ void Sound::setVolume(double volume)
4748
/*! Starts the playback of the sound. */
4849
void Sound::start()
4950
{
51+
// Stop sounds in clones (#538)
52+
stopCloneSounds();
5053
impl->player->start();
5154
}
5255

5356
/*! Stops the playback of the sound. */
5457
void Sound::stop()
5558
{
59+
// Stop sounds in clones (#538)
60+
stopCloneSounds();
5661
impl->player->stop();
5762
}
5863

@@ -95,3 +100,30 @@ void Sound::processData(unsigned int size, void *data)
95100
if (!impl->player->load(size, data, impl->rate))
96101
std::cerr << "Failed to load sound " << name() << std::endl;
97102
}
103+
104+
void Sound::stopCloneSounds()
105+
{
106+
if (impl->target && !impl->target->isStage()) {
107+
Sprite *sprite = static_cast<Sprite *>(impl->target);
108+
109+
if (sprite->isClone())
110+
sprite = sprite->cloneSprite();
111+
112+
// Stop the sound in the sprite (clone root)
113+
auto sound = sprite->soundAt(sprite->findSound(name()));
114+
115+
if (sound && sound.get() != this)
116+
sound->impl->player->stop();
117+
118+
// Stop the sound in clones
119+
const auto &clones = sprite->clones();
120+
121+
for (auto clone : clones) {
122+
auto sound = clone->soundAt(clone->findSound(name()));
123+
assert(sound);
124+
125+
if (sound && sound.get() != this)
126+
sound->impl->player->stop();
127+
}
128+
}
129+
}

test/assets/sound_test.cpp

Lines changed: 50 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
#include <scratchcpp/sound.h>
2-
#include <scratchcpp/target.h>
2+
#include <scratchcpp/sprite.h>
33
#include <scratch/sound_p.h>
44
#include <audiooutputmock.h>
55
#include <audioplayermock.h>
6+
#include <enginemock.h>
67

78
#include "../common.h"
89

@@ -119,28 +120,66 @@ TEST_F(SoundTest, Target)
119120

120121
TEST_F(SoundTest, Clone)
121122
{
122-
Sound sound("sound1", "a", "wav");
123-
sound.setRate(44100);
124-
sound.setSampleCount(10000);
123+
auto sound = std::make_shared<Sound>("sound1", "a", "wav");
124+
sound->setRate(44100);
125+
sound->setSampleCount(10000);
125126

126127
const char *data = "abc";
127128
void *dataPtr = const_cast<void *>(static_cast<const void *>(data));
128129

129130
EXPECT_CALL(*m_player, isLoaded()).WillOnce(Return(false));
130131
EXPECT_CALL(*m_player, load(3, dataPtr, 44100)).WillOnce(Return(true));
131-
sound.setData(3, dataPtr);
132+
sound->setData(3, dataPtr);
132133

133134
auto clonePlayer = std::make_shared<AudioPlayerMock>();
134135
EXPECT_CALL(m_playerFactory, createAudioPlayer()).WillOnce(Return(clonePlayer));
135136
EXPECT_CALL(*clonePlayer, loadCopy(m_player.get())).WillOnce(Return(true));
136137
EXPECT_CALL(*m_player, volume()).WillOnce(Return(0.45));
137138
EXPECT_CALL(*clonePlayer, setVolume(0.45));
138139
EXPECT_CALL(*clonePlayer, isLoaded()).WillOnce(Return(true));
139-
auto clone = sound.clone();
140+
auto clone = sound->clone();
140141
ASSERT_TRUE(clone);
141-
ASSERT_EQ(clone->name(), sound.name());
142-
ASSERT_EQ(clone->id(), sound.id());
143-
ASSERT_EQ(clone->dataFormat(), sound.dataFormat());
144-
ASSERT_EQ(clone->rate(), sound.rate());
145-
ASSERT_EQ(clone->sampleCount(), sound.sampleCount());
142+
ASSERT_EQ(clone->name(), sound->name());
143+
ASSERT_EQ(clone->id(), sound->id());
144+
ASSERT_EQ(clone->dataFormat(), sound->dataFormat());
145+
ASSERT_EQ(clone->rate(), sound->rate());
146+
ASSERT_EQ(clone->sampleCount(), sound->sampleCount());
147+
148+
// Stopping/starting the sound should stop its clones
149+
auto anotherPlayer = std::make_shared<AudioPlayerMock>();
150+
EXPECT_CALL(m_playerFactory, createAudioPlayer()).WillOnce(Return(anotherPlayer));
151+
auto another = std::make_shared<Sound>("another", "c", "mp3");
152+
Sprite sprite;
153+
EngineMock engine;
154+
sprite.setEngine(&engine);
155+
156+
EXPECT_CALL(engine, cloneLimit()).WillOnce(Return(-1));
157+
EXPECT_CALL(engine, initClone);
158+
EXPECT_CALL(engine, requestRedraw);
159+
EXPECT_CALL(engine, moveSpriteBehindOther);
160+
auto spriteClone = sprite.clone();
161+
162+
EXPECT_CALL(*anotherPlayer, setVolume).Times(2);
163+
EXPECT_CALL(*m_player, setVolume);
164+
EXPECT_CALL(*clonePlayer, setVolume);
165+
sprite.addSound(another);
166+
sprite.addSound(sound);
167+
spriteClone->addSound(another);
168+
spriteClone->addSound(clone);
169+
170+
EXPECT_CALL(*m_player, stop());
171+
EXPECT_CALL(*clonePlayer, stop());
172+
sound->stop();
173+
174+
EXPECT_CALL(*m_player, stop());
175+
EXPECT_CALL(*clonePlayer, stop());
176+
clone->stop();
177+
178+
EXPECT_CALL(*m_player, start());
179+
EXPECT_CALL(*clonePlayer, stop());
180+
sound->start();
181+
182+
EXPECT_CALL(*m_player, stop());
183+
EXPECT_CALL(*clonePlayer, start());
184+
clone->start();
146185
}

test/blocks/sound_blocks_test.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
#include <scratchcpp/block.h>
33
#include <scratchcpp/input.h>
44
#include <scratchcpp/field.h>
5-
#include <scratchcpp/target.h>
65
#include <scratchcpp/sound.h>
76
#include <scratch/sound_p.h>
87
#include <enginemock.h>
98
#include <audiooutputmock.h>
109
#include <audioplayermock.h>
10+
#include <targetmock.h>
1111

1212
#include "../common.h"
1313
#include "blocks/soundblocks.h"
@@ -212,7 +212,8 @@ TEST_F(SoundBlocksTest, PlayImpl)
212212
EXPECT_CALL(*player1, setVolume);
213213
EXPECT_CALL(*player2, setVolume);
214214
EXPECT_CALL(*player3, setVolume);
215-
Target target;
215+
TargetMock target;
216+
EXPECT_CALL(target, isStage()).WillRepeatedly(Return(true));
216217
target.addSound(std::make_shared<Sound>("some sound", "", ""));
217218
target.addSound(std::make_shared<Sound>("test", "", ""));
218219
target.addSound(std::make_shared<Sound>("another sound", "", ""));
@@ -412,7 +413,8 @@ TEST_F(SoundBlocksTest, PlayUntilDoneImpl)
412413
EXPECT_CALL(*player1, setVolume);
413414
EXPECT_CALL(*player2, setVolume);
414415
EXPECT_CALL(*player3, setVolume);
415-
Target target;
416+
TargetMock target;
417+
EXPECT_CALL(target, isStage()).WillRepeatedly(Return(true));
416418
target.addSound(std::make_shared<Sound>("some sound", "", ""));
417419
target.addSound(std::make_shared<Sound>("test", "", ""));
418420
target.addSound(std::make_shared<Sound>("another sound", "", ""));

test/engine/engine_test.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -275,9 +275,7 @@ TEST(EngineTest, StopSounds)
275275

276276
auto engine = p.engine();
277277

278-
EXPECT_CALL(*player1, isPlaying()).WillOnce(Return(false));
279-
EXPECT_CALL(*player2, isPlaying()).WillOnce(Return(true));
280-
EXPECT_CALL(*player3, isPlaying()).WillOnce(Return(true));
278+
EXPECT_CALL(*player1, stop());
281279
EXPECT_CALL(*player2, stop());
282280
EXPECT_CALL(*player3, stop());
283281
engine->stopSounds();

0 commit comments

Comments
 (0)