diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c032c5f5..79e664982 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. ## [Unreleased] ### Added - FLA export - accessibility for AS3 files +- [#2375] Sound sync event/start/stop handling (for playback in FFDec) + +### Fixed +- [#2375] Added limit of simultaneously played sounds ## [22.0.1] - 2024-11-20 ### Added @@ -3672,6 +3676,7 @@ Major version of SWF to XML export changed to 2. [alpha 9]: https://github.com/jindrapetrik/jpexs-decompiler/compare/alpha8...alpha9 [alpha 8]: https://github.com/jindrapetrik/jpexs-decompiler/compare/alpha7...alpha8 [alpha 7]: https://github.com/jindrapetrik/jpexs-decompiler/releases/tag/alpha7 +[#2375]: https://www.free-decompiler.com/flash/issues/2375 [#2366]: https://www.free-decompiler.com/flash/issues/2366 [#2367]: https://www.free-decompiler.com/flash/issues/2367 [#2372]: https://www.free-decompiler.com/flash/issues/2372 diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java index 6b60d1a72..a6b362bff 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java @@ -1701,9 +1701,11 @@ public class Timeline { */ public void getSounds(int frame, int time, ButtonTag mouseOverButton, int mouseButton, List sounds, List soundClasses, List soundInfos) { Frame fr = getFrame(frame); - sounds.addAll(fr.sounds); - soundClasses.addAll(fr.soundClasses); - soundInfos.addAll(fr.soundInfos); + if (time == 0) { + sounds.addAll(fr.sounds); + soundClasses.addAll(fr.soundClasses); + soundInfos.addAll(fr.soundInfos); + } for (int d = maxDepth; d >= 0; d--) { DepthState ds = fr.layers.get(d); if (ds != null) { @@ -1724,7 +1726,7 @@ public class Timeline { } } } - ((Timelined) c).getTimeline().getSounds(dframe, time, mouseOverButton, mouseButton, sounds, soundClasses, soundInfos); + ((Timelined) c).getTimeline().getSounds(dframe, 0, mouseOverButton, mouseButton, sounds, soundClasses, soundInfos); } } } @@ -1849,6 +1851,9 @@ public class Timeline { if (character == null) { continue; } + if (!frameObj.sounds.isEmpty()) { //consider timelines with sound as not singleframe + return false; + } if (character instanceof DrawableTag) { DrawableTag drawable = (DrawableTag) character; if (!drawable.isSingleFrame()) { diff --git a/libsrc/ffdec_lib/testdata/sounds/sounds.swf b/libsrc/ffdec_lib/testdata/sounds/sounds.swf index 7d3d85e55..b3881b1c5 100644 Binary files a/libsrc/ffdec_lib/testdata/sounds/sounds.swf and b/libsrc/ffdec_lib/testdata/sounds/sounds.swf differ diff --git a/libsrc/ffdec_lib/testdata/sounds/sounds/DOMDocument.xml b/libsrc/ffdec_lib/testdata/sounds/sounds/DOMDocument.xml index fcc756e13..917546bf9 100644 --- a/libsrc/ffdec_lib/testdata/sounds/sounds/DOMDocument.xml +++ b/libsrc/ffdec_lib/testdata/sounds/sounds/DOMDocument.xml @@ -3,6 +3,7 @@ + @@ -18,9 +19,10 @@ + - + @@ -85,7 +87,7 @@ - + @@ -349,13 +351,13 @@ - + - Stop + 009 Stop @@ -364,6 +366,31 @@ + + + + + + + + + 010 Sync + + + + + + + + + + + + + + + + @@ -371,6 +398,15 @@ + + + + + + + + + @@ -382,14 +418,5 @@ - - - - - - - - - \ No newline at end of file diff --git a/libsrc/ffdec_lib/testdata/sounds/sounds/LIBRARY/19_20.wav b/libsrc/ffdec_lib/testdata/sounds/sounds/LIBRARY/19_20.wav new file mode 100644 index 000000000..70380e7e6 Binary files /dev/null and b/libsrc/ffdec_lib/testdata/sounds/sounds/LIBRARY/19_20.wav differ diff --git a/libsrc/ffdec_lib/testdata/sounds/sounds/LIBRARY/Symbol 4.xml b/libsrc/ffdec_lib/testdata/sounds/sounds/LIBRARY/Symbol 4.xml new file mode 100644 index 000000000..beb27fdb6 --- /dev/null +++ b/libsrc/ffdec_lib/testdata/sounds/sounds/LIBRARY/Symbol 4.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libsrc/ffdec_lib/testdata/sounds/sounds/META-INF/metadata.xml b/libsrc/ffdec_lib/testdata/sounds/sounds/META-INF/metadata.xml index a0c53ca4a..30603b8fc 100644 --- a/libsrc/ffdec_lib/testdata/sounds/sounds/META-INF/metadata.xml +++ b/libsrc/ffdec_lib/testdata/sounds/sounds/META-INF/metadata.xml @@ -5,8 +5,8 @@ xmlns:xmp="http://ns.adobe.com/xap/1.0/"> Adobe Flash Professional CS6 - build 481 2021-03-14T08:29:20+01:00 - 2023-12-01T10:51:51-08:00 - 2023-12-01T10:51:51-08:00 + 2024-11-30T09:27:52-08:00 + 2024-11-30T09:27:52-08:00 @@ -16,7 +16,7 @@ xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmlns:stEvt="http://ns.adobe.com/xap/1.0/sType/ResourceEvent#" xmlns:stRef="http://ns.adobe.com/xap/1.0/sType/ResourceRef#"> - xmp.iid:EF6458507290EE1191BEAA90054676FA + xmp.iid:DBB644B932AFEF11A208DFE3564218EE xmp.did:21E4449F4B7EED119DEE8735AA8CEAC4 xmp.did:D6D3FE199784EB1187FEAE6972EC5115 @@ -159,6 +159,12 @@ 2021-03-14T08:29:20+01:00 Adobe Flash Professional CS6 - build 481 + + created + xmp.iid:DBB644B932AFEF11A208DFE3564218EE + 2021-03-14T08:29:20+01:00 + Adobe Flash Professional CS6 - build 481 + diff --git a/libsrc/ffdec_lib/testdata/sounds/sounds/bin/M 9 1732989871.dat b/libsrc/ffdec_lib/testdata/sounds/sounds/bin/M 9 1732989871.dat new file mode 100644 index 000000000..00c7f2f8d Binary files /dev/null and b/libsrc/ffdec_lib/testdata/sounds/sounds/bin/M 9 1732989871.dat differ diff --git a/libsrc/ffdec_lib/testdata/sounds/sounds/bin/SymDepend.cache b/libsrc/ffdec_lib/testdata/sounds/sounds/bin/SymDepend.cache index ff06939ff..e5bfd3ef5 100644 Binary files a/libsrc/ffdec_lib/testdata/sounds/sounds/bin/SymDepend.cache and b/libsrc/ffdec_lib/testdata/sounds/sounds/bin/SymDepend.cache differ diff --git a/src/com/jpexs/decompiler/flash/gui/ImagePanel.java b/src/com/jpexs/decompiler/flash/gui/ImagePanel.java index 8d36cd07b..f672f245a 100644 --- a/src/com/jpexs/decompiler/flash/gui/ImagePanel.java +++ b/src/com/jpexs/decompiler/flash/gui/ImagePanel.java @@ -132,6 +132,9 @@ import org.pushingpixels.substance.api.SubstanceSkin; */ public final class ImagePanel extends JPanel implements MediaDisplay { + + private static final int MAX_SOUND_CHANNELS = 8; //TODO: Maybe add to Advanced settings + private static final Logger logger = Logger.getLogger(ImagePanel.class.getName()); private final List listeners = new ArrayList<>(); @@ -3689,7 +3692,7 @@ public final class ImagePanel extends JPanel implements MediaDisplay { } } - if (!shownAgain && autoPlayed) { + if (autoPlayed) { //!shownAgain if (!muted) { List sounds = new ArrayList<>(); List soundClasses = new ArrayList<>(); @@ -3870,13 +3873,37 @@ public final class ImagePanel extends JPanel implements MediaDisplay { } private void playSound(SoundTag st, SOUNDINFO soundInfo, Timer thisTimer) { + synchronized (ImagePanel.this) { + if (soundInfo.syncNoMultiple || soundInfo.syncStop) { + for (int s = soundPlayers.size() - 1; s >= 0; s--) { + SoundTagPlayer sp = soundPlayers.get(s); + if (sp.getTag() == st) { + if (soundInfo.syncNoMultiple) { + //already playing same sound, return + return; + } + if (soundInfo.syncStop) { + sp.stop(); + } + } + } + + if (soundInfo.syncStop) { + return; + } + } + + if (soundPlayers.size() > MAX_SOUND_CHANNELS) { + return; + } + } final SoundTagPlayer sp; try { int loopCount = 1; if (soundInfo != null && soundInfo.hasLoops) { loopCount = Math.max(1, soundInfo.loopCount); } - + sp = new SoundTagPlayer(soundInfo, st, loopCount, false, resample); sp.addEventListener(new MediaDisplayListener() { @Override @@ -4009,13 +4036,7 @@ public final class ImagePanel extends JPanel implements MediaDisplay { long delay = getMsPerFrame(); if (isSingleFrame) { drawFrame(thisTimer, true); - /*synchronized (ImagePanel.this) { - thisTimer.cancel(); - if (timer == thisTimer) { - timer = null; - } - }*/ - + fireMediaDisplayStateChanged(); } else { //Time before drawing current frame diff --git a/src/com/jpexs/decompiler/flash/gui/SoundTagPlayer.java b/src/com/jpexs/decompiler/flash/gui/SoundTagPlayer.java index 3325a082b..7144c3e7c 100644 --- a/src/com/jpexs/decompiler/flash/gui/SoundTagPlayer.java +++ b/src/com/jpexs/decompiler/flash/gui/SoundTagPlayer.java @@ -88,6 +88,14 @@ public class SoundTagPlayer implements MediaDisplay { private boolean active = false; + private static int totalInstances = 0; + + private int instanceId = totalInstances++; + + public int getInstanceId() { + return instanceId; + } + private boolean getActiveFlag() { synchronized (playLock) { return active; @@ -190,6 +198,8 @@ public class SoundTagPlayer implements MediaDisplay { playLoop(); } catch (LineUnavailableException ex) { Logger.getLogger(SoundTagPlayer.class.getName()).log(Level.SEVERE, null, ex); + } catch (Exception ex) { + Logger.getLogger(SoundTagPlayer.class.getName()).log(Level.SEVERE, null, ex); } } }; @@ -376,6 +386,9 @@ public class SoundTagPlayer implements MediaDisplay { firePlayingFinished(); if (getClosedFlag()) { + sourceLine.drain(); + sourceLine.stop(); + sourceLine.close(); return; } synchronized (thread) { @@ -400,6 +413,8 @@ public class SoundTagPlayer implements MediaDisplay { Logger.getLogger(SoundTagPlayer.class.getName()).log(Level.SEVERE, null, ex); } } + } else { + firePlayingFinished(); } break; } @@ -455,6 +470,10 @@ public class SoundTagPlayer implements MediaDisplay { return null; } + public SoundTag getTag() { + return tag; + } + @Override public void setLoop(boolean loop) { synchronized (playLock) {