Skip to content

Commit

Permalink
Added #2132 Show and export streamed sound (SoundStreamHead/SoundStre…
Browse files Browse the repository at this point in the history
…amBlock) in frame ranges

Fixed #1194 FLA Export - stream sound export
  • Loading branch information
jindrapetrik committed Dec 2, 2023
1 parent d5ea4fc commit 42d38aa
Show file tree
Hide file tree
Showing 20 changed files with 645 additions and 300 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ All notable changes to this project will be documented in this file.
- [#2131] Breakpoint list dialog
- ExportAssets tag - show first item as description in the tree when there is only single item
- [#2134] FLA Export - split main timeline into scenes when DefineSceneAndFrameLabelData tag is present
- [#2132] Show and export streamed sound (SoundStreamHead/SoundStreamBlock) in frame ranges

### Fixed
- [#2021], [#2000] Caret position in editors when using tabs and / or unicode
Expand Down Expand Up @@ -64,6 +65,7 @@ All notable changes to this project will be documented in this file.
- Wordrapping long words in DefineEditText
- [#2133] Linux/Mac - ffdec.sh not correctly parsing java build number on javas without it
- [#2135] FLA Export - framescripts handling when addFrameScript uses Multinames instead of QNames
- [#1194] FLA Export - stream sound export

### Changed
- [#2120] Exported assets no longer take names from assigned classes if there is more than 1 assigned class
Expand Down Expand Up @@ -3324,6 +3326,7 @@ Major version of SWF to XML export changed to 2.
[#2131]: https://www.free-decompiler.com/flash/issues/2131
[#2124]: https://www.free-decompiler.com/flash/issues/2124
[#2134]: https://www.free-decompiler.com/flash/issues/2134
[#2132]: https://www.free-decompiler.com/flash/issues/2132
[#2021]: https://www.free-decompiler.com/flash/issues/2021
[#2000]: https://www.free-decompiler.com/flash/issues/2000
[#2116]: https://www.free-decompiler.com/flash/issues/2116
Expand All @@ -3335,6 +3338,7 @@ Major version of SWF to XML export changed to 2.
[#2053]: https://www.free-decompiler.com/flash/issues/2053
[#2133]: https://www.free-decompiler.com/flash/issues/2133
[#2135]: https://www.free-decompiler.com/flash/issues/2135
[#1194]: https://www.free-decompiler.com/flash/issues/1194
[#2120]: https://www.free-decompiler.com/flash/issues/2120
[#1130]: https://www.free-decompiler.com/flash/issues/1130
[#1220]: https://www.free-decompiler.com/flash/issues/1220
Expand Down Expand Up @@ -3765,7 +3769,6 @@ Major version of SWF to XML export changed to 2.
[#1200]: https://www.free-decompiler.com/flash/issues/1200
[#1198]: https://www.free-decompiler.com/flash/issues/1198
[#1205]: https://www.free-decompiler.com/flash/issues/1205
[#1194]: https://www.free-decompiler.com/flash/issues/1194
[#1210]: https://www.free-decompiler.com/flash/issues/1210
[#1217]: https://www.free-decompiler.com/flash/issues/1217
[#1244]: https://www.free-decompiler.com/flash/issues/1244
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
import com.jpexs.decompiler.flash.tags.gfx.DefineCompactedFont;
import com.jpexs.decompiler.flash.timeline.DepthState;
import com.jpexs.decompiler.flash.timeline.Frame;
import com.jpexs.decompiler.flash.timeline.SoundStreamFrameRange;
import com.jpexs.decompiler.flash.timeline.Timelined;
import com.jpexs.decompiler.flash.treeitems.TreeItem;
import com.jpexs.decompiler.flash.types.BUTTONCONDACTION;
Expand Down Expand Up @@ -261,7 +262,13 @@ public SWFHeader exportSwf(OutputStream os, TreeItem treeItem, Color backgroundC

List<SoundStreamBlockTag> soundFrames = new ArrayList<>();
if (treeItem instanceof SoundStreamHeadTypeTag) {
soundFrames = ((SoundStreamHeadTypeTag) treeItem).getBlocks();
SoundStreamHeadTypeTag head = (SoundStreamHeadTypeTag) treeItem;
for (SoundStreamFrameRange range : head.getRanges()) {
soundFrames.addAll(range.blocks);
}
}
if (treeItem instanceof SoundStreamFrameRange) {
soundFrames = ((SoundStreamFrameRange) treeItem).blocks;
frameCount = soundFrames.size();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import com.jpexs.decompiler.flash.tags.base.SoundTag;
import com.jpexs.decompiler.flash.tags.gfx.DefineExternalSound;
import com.jpexs.decompiler.flash.tags.gfx.DefineExternalStreamSound;
import com.jpexs.decompiler.flash.timeline.SoundStreamFrameRange;
import com.jpexs.decompiler.flash.types.sound.SoundExportFormat;
import com.jpexs.decompiler.flash.types.sound.SoundFormat;
import com.jpexs.helpers.ByteArrayRange;
Expand All @@ -58,8 +59,17 @@
* @author JPEXS
*/
public class SoundExporter {

public List<File> exportSounds(AbortRetryIgnoreHandler handler, String outdir, ReadOnlyTagList tags, final SoundExportSettings settings, EventListener evl) throws IOException, InterruptedException {
List<SoundTag> sounds = new ArrayList<>();
for (Tag t : tags) {
if (t instanceof SoundTag) {
sounds.add((SoundTag) t);
}
}
return exportSounds(handler, outdir, sounds, settings, evl);
}

public List<File> exportSounds(AbortRetryIgnoreHandler handler, String outdir, List<SoundTag> tags, final SoundExportSettings settings, EventListener evl) throws IOException, InterruptedException {
List<File> ret = new ArrayList<>();
if (Thread.currentThread().isInterrupted()) {
return ret;
Expand All @@ -72,75 +82,64 @@ public List<File> exportSounds(AbortRetryIgnoreHandler handler, String outdir, R
File foutdir = new File(outdir);
Path.createDirectorySafe(foutdir);

int count = 0;
for (Tag t : tags) {
if (t instanceof SoundTag) {
count++;
}
}

if (count == 0) {
if (tags.isEmpty()) {
return ret;
}

int currentIndex = 1;
for (Tag t : tags) {
if (t instanceof SoundTag) {
if (evl != null) {
evl.handleExportingEvent("sound", currentIndex, count, t.getName());
}

final SoundTag st = (SoundTag) t;

String ext = ".wav";
SoundFormat fmt = st.getSoundFormat();
switch (fmt.getNativeExportFormat()) {
case MP3:
if (settings.mode.hasMP3()) {
ext = ".mp3";
}
break;
case FLV:
if (settings.mode.hasFlv()) {
ext = ".flv";
}
break;
}
if (settings.mode == SoundExportMode.FLV) {
ext = ".flv";
}
for (SoundTag st : tags) {
if (evl != null) {
evl.handleExportingEvent("sound", currentIndex, tags.size(), st.getName());
}

final File file = new File(outdir + File.separator + Helper.makeFileName(st.getCharacterExportFileName()) + ext);
new RetryTask(() -> {
try (OutputStream os = new BufferedOutputStream(new FileOutputStream(file))) {
exportSound(os, st, settings.mode);
String ext = ".wav";
SoundFormat fmt = st.getSoundFormat();
switch (fmt.getNativeExportFormat()) {
case MP3:
if (settings.mode.hasMP3()) {
ext = ".mp3";
}
}, handler).run();

Set<String> classNames = (st instanceof CharacterTag) ? ((CharacterTag) st).getClassNames() : new HashSet<>();
if (Configuration.as3ExportNamesUseClassNamesOnly.get() && !classNames.isEmpty()) {
for (String className : classNames) {
File classFile = new File(outdir + File.separator + Helper.makeFileName(className + ext));
new RetryTask(() -> {
Files.copy(file.toPath(), classFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
}, handler).run();
ret.add(classFile);
break;
case FLV:
if (settings.mode.hasFlv()) {
ext = ".flv";
}
file.delete();
} else {
ret.add(file);
}

if (Thread.currentThread().isInterrupted()) {
break;
}
}
if (settings.mode == SoundExportMode.FLV) {
ext = ".flv";
}

if (evl != null) {
evl.handleExportedEvent("sound", currentIndex, count, t.getName());
final File file = new File(outdir + File.separator + Helper.makeFileName(st.getCharacterExportFileName()) + ext);
new RetryTask(() -> {
try (OutputStream os = new BufferedOutputStream(new FileOutputStream(file))) {
exportSound(os, st, settings.mode);
}
}, handler).run();

Set<String> classNames = (st instanceof CharacterTag) ? ((CharacterTag) st).getClassNames() : new HashSet<>();
if (Configuration.as3ExportNamesUseClassNamesOnly.get() && !classNames.isEmpty()) {
for (String className : classNames) {
File classFile = new File(outdir + File.separator + Helper.makeFileName(className + ext));
new RetryTask(() -> {
Files.copy(file.toPath(), classFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
}, handler).run();
ret.add(classFile);
}
file.delete();
} else {
ret.add(file);
}

if (Thread.currentThread().isInterrupted()) {
break;
}

currentIndex++;
if (evl != null) {
evl.handleExportedEvent("sound", currentIndex, tags.size(), st.getName());
}

currentIndex++;
}
return ret;
}
Expand Down Expand Up @@ -168,12 +167,22 @@ public void exportSound(OutputStream fos, SoundTag st, SoundExportMode mode) thr
for (ByteArrayRange data : datas) {
flv.writeTag(new FLVTAG(0, new AUDIODATA(st.getSoundFormatId(), st.getSoundRate(), st.getSoundSize(), st.getSoundType(), data.getRangeData())));
}
} else if (st instanceof SoundStreamHeadTypeTag) {
SoundStreamHeadTypeTag sh = (SoundStreamHeadTypeTag) st;
} else if ((st instanceof SoundStreamFrameRange) || (st instanceof SoundStreamHeadTypeTag)) {
List<SoundStreamBlockTag> blocks;
if (st instanceof SoundStreamHeadTypeTag) {
blocks = new ArrayList<>();
SoundStreamHeadTypeTag head = (SoundStreamHeadTypeTag) st;
for (SoundStreamFrameRange range : head.getRanges()) {
blocks.addAll(range.blocks);
}
} else {
blocks = ((SoundStreamFrameRange) st).blocks;
}

SoundStreamFrameRange sh = (SoundStreamFrameRange) st;
FLVOutputStream flv = new FLVOutputStream(fos);
flv.writeHeader(true, false);
List<SoundStreamBlockTag> blocks = sh.getBlocks();


int ms = (int) (1000.0 / ((Tag) st).getSwf().frameRate);
for (int b = 0; b < blocks.size(); b++) {
byte[] data = blocks.get(b).streamSoundData.getRangeData();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import com.jpexs.decompiler.flash.tags.base.SoundStreamHeadTypeTag;
import com.jpexs.decompiler.flash.tags.base.SoundTag;
import com.jpexs.decompiler.flash.tags.base.UnsupportedSamplingRateException;
import com.jpexs.decompiler.flash.timeline.SoundStreamFrameRange;
import com.jpexs.decompiler.flash.timeline.Timelined;
import com.jpexs.decompiler.flash.types.sound.MP3FRAME;
import com.jpexs.decompiler.flash.types.sound.MP3SOUNDDATA;
Expand Down Expand Up @@ -329,7 +330,14 @@ public boolean importSoundStream(SoundStreamHeadTypeTag streamHead, InputStream

ByteArrayInputStream bais = uncompressedSoundData == null ? null : new ByteArrayInputStream(uncompressedSoundData);

List<SoundStreamBlockTag> existingBlocks = streamHead.getBlocks();
List<SoundStreamFrameRange> ranges = streamHead.getRanges();

List<SoundStreamBlockTag> existingBlocks = new ArrayList<>();
for (SoundStreamFrameRange range : ranges) {
existingBlocks.addAll(range.blocks);
}


int startFrame = 0;
Timelined timelined = streamHead.getTimelined();
if (!existingBlocks.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,4 +237,9 @@ public void setSoundCompression(int soundCompression) {
public void setSoundRate(int soundRate) {
this.soundRate = soundRate;
}

@Override
public String getFlaExportName() {
return "sound" + getCharacterId();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.SWFOutputStream;
import com.jpexs.decompiler.flash.tags.base.SoundStreamHeadTypeTag;
import com.jpexs.decompiler.flash.timeline.SoundStreamFrameRange;
import com.jpexs.decompiler.flash.timeline.Timeline;
import com.jpexs.decompiler.flash.types.BasicType;
import com.jpexs.decompiler.flash.types.annotations.Conditional;
Expand Down Expand Up @@ -191,9 +192,9 @@ public boolean getSoundType() {
}

@Override
public List<SoundStreamBlockTag> getBlocks() {
public List<SoundStreamFrameRange> getRanges() {
Timeline timeline = swf.getTimeline();
List<SoundStreamBlockTag> ret = timeline.getSoundStreamBlocks(this);
List<SoundStreamFrameRange> ret = timeline.getSoundStreamBlocks(this);
return ret;

}
Expand All @@ -206,14 +207,16 @@ public boolean importSupported() {
@Override
public List<ByteArrayRange> getRawSoundData() {
List<ByteArrayRange> ret = new ArrayList<>();
List<SoundStreamBlockTag> blocks = getBlocks();
if (blocks != null) {
for (SoundStreamBlockTag block : blocks) {
ByteArrayRange data = block.streamSoundData;
if (streamSoundCompression == SoundFormat.FORMAT_MP3) {
ret.add(data.getSubRange(4, data.getLength() - 4));
} else {
ret.add(data);
List<SoundStreamFrameRange> frameRanges = getRanges();
if (frameRanges != null) {
for (SoundStreamFrameRange range : frameRanges) {
for (SoundStreamBlockTag block : range.blocks) {
ByteArrayRange data = block.streamSoundData;
if (streamSoundCompression == SoundFormat.FORMAT_MP3) {
ret.add(data.getSubRange(4, data.getLength() - 4));
} else {
ret.add(data);
}
}
}
}
Expand All @@ -222,7 +225,11 @@ public List<ByteArrayRange> getRawSoundData() {

@Override
public long getTotalSoundSampleCount() {
return getBlocks().size() * streamSoundSampleCount;
int blockCount = 0;
for (SoundStreamFrameRange range : getRanges()) {
blockCount += range.blocks.size();
}
return blockCount * streamSoundSampleCount;
}

@Override
Expand Down Expand Up @@ -278,4 +285,9 @@ public void setSoundCompression(int soundCompression) {
public void setSoundRate(int soundRate) {
this.streamSoundRate = soundRate;
}

@Override
public String getFlaExportName() {
return "sound" + getCharacterId();
}
}
Loading

0 comments on commit 42d38aa

Please sign in to comment.