FLA export - sounds

Wav export (for ADPCM sounds)
This commit is contained in:
Jindra Petk
2013-05-18 16:42:07 +02:00
parent 3c83eefc5c
commit db6f121ca8
13 changed files with 518 additions and 84 deletions

View File

@@ -562,7 +562,7 @@ public class Main {
System.out.println("Exporting movies...");
exfile.exportMovies(outDir.getAbsolutePath() + File.separator + "movies");
System.out.println("Exporting sounds...");
exfile.exportSounds(outDir.getAbsolutePath() + File.separator + "sounds", true);
exfile.exportSounds(outDir.getAbsolutePath() + File.separator + "sounds", true, true);
System.out.println("Exporting binaryData...");
exfile.exportBinaryData(outDir.getAbsolutePath() + File.separator + "binaryData");
System.out.println("Exporting texts...");
@@ -587,7 +587,7 @@ public class Main {
exfile.exportMovies(outDir.getAbsolutePath());
exportOK = true;
} else if (exportFormat.equals("sound")) {
exfile.exportSounds(outDir.getAbsolutePath(), true);
exfile.exportSounds(outDir.getAbsolutePath(), true, true);
exportOK = true;
} else if (exportFormat.equals("binaryData")) {
exfile.exportBinaryData(outDir.getAbsolutePath());

View File

@@ -74,6 +74,7 @@ import com.jpexs.decompiler.flash.tags.base.ImageTag;
import com.jpexs.decompiler.flash.tags.base.ShapeTag;
import com.jpexs.decompiler.flash.tags.base.TextTag;
import com.jpexs.decompiler.flash.types.RECT;
import com.jpexs.decompiler.flash.types.sound.AdpcmDecoder;
import com.jpexs.decompiler.flash.xfl.XFLConverter;
import java.io.*;
import java.util.ArrayList;
@@ -604,12 +605,13 @@ public class SWF {
exportMovies(outdir, tags);
}
public void exportSounds(String outdir, boolean mp3) throws IOException {
exportSounds(outdir, tags, mp3);
public void exportSounds(String outdir, boolean mp3, boolean wave) throws IOException {
exportSounds(outdir, tags, mp3, wave);
}
public byte[] exportSound(Tag t) throws IOException {
boolean mp3 = true;
boolean wave = true;
ByteArrayOutputStream fos = new ByteArrayOutputStream();
int id = 0;
if (t instanceof DefineSoundTag) {
@@ -619,9 +621,12 @@ public class SWF {
if (t instanceof DefineSoundTag) {
DefineSoundTag st = (DefineSoundTag) t;
if ((st.soundFormat == DefineSoundTag.FORMAT_MP3) && mp3) {
if ((st.soundFormat == DefineSoundTag.FORMAT_ADPCM) && wave) {
fos = new ByteArrayOutputStream();
fos.write(st.soundData);
createWavFromAdpcm(fos, st.soundRate, st.soundSize, st.soundType, st.soundData);
} else if ((st.soundFormat == DefineSoundTag.FORMAT_MP3) && mp3) {
fos = new ByteArrayOutputStream();
fos.write(st.soundData, 2, st.soundData.length - 2);
} else {
fos = new ByteArrayOutputStream();
FLVOutputStream flv = new FLVOutputStream(fos);
@@ -634,7 +639,15 @@ public class SWF {
List<SoundStreamBlockTag> blocks = new ArrayList<SoundStreamBlockTag>();
List<Object> objs = new ArrayList<Object>(this.tags);
populateSoundStreamBlocks(objs, t, blocks);
if ((shead.getSoundFormat() == 2) && mp3) {
if ((shead.getSoundFormat() == DefineSoundTag.FORMAT_ADPCM) && wave) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
for (int b = 0; b < blocks.size(); b++) {
byte data[] = blocks.get(b).getData(SWF.DEFAULT_VERSION);
baos.write(data);
}
fos = new ByteArrayOutputStream();
createWavFromAdpcm(fos, shead.getSoundRate(), shead.getSoundSize(), shead.getSoundType(), baos.toByteArray());
} else if ((shead.getSoundFormat() == DefineSoundTag.FORMAT_MP3) && mp3) {
fos = new ByteArrayOutputStream();
for (int b = 0; b < blocks.size(); b++) {
byte data[] = blocks.get(b).getData(SWF.DEFAULT_VERSION);
@@ -658,7 +671,61 @@ public class SWF {
return fos.toByteArray();
}
public void exportSounds(String outdir, List<Tag> tags, boolean mp3) throws IOException {
private static void writeLE(OutputStream os, long val, int size) throws IOException {
for (int i = 0; i < size; i++) {
os.write((int) (val & 0xff));
val = val >> 8;
}
}
private static void createWavFromAdpcm(OutputStream fos, int soundRate, int soundSize, int soundType, byte data[]) throws IOException {
try {
byte pcmData[] = AdpcmDecoder.decode(data, soundType == 1 ? true : false);
ByteArrayOutputStream subChunk1Data = new ByteArrayOutputStream();
int audioFormat = 1; //PCM
writeLE(subChunk1Data, audioFormat, 2);
int numChannels = soundType == 1 ? 2 : 1;
writeLE(subChunk1Data, numChannels, 2);
int rateMap[] = {5512, 11025, 22050, 44100};
int sampleRate = rateMap[soundRate];
writeLE(subChunk1Data, sampleRate, 4);
int bitsPerSample = soundSize == 1 ? 16 : 8;
int byteRate = sampleRate * numChannels * bitsPerSample / 8;
writeLE(subChunk1Data, byteRate, 4);
int blockAlign = numChannels * bitsPerSample / 8;
writeLE(subChunk1Data, blockAlign, 2);
writeLE(subChunk1Data, bitsPerSample, 2);
ByteArrayOutputStream chunks = new ByteArrayOutputStream();
chunks.write("fmt ".getBytes());
byte subChunk1DataBytes[] = subChunk1Data.toByteArray();
writeLE(chunks, subChunk1DataBytes.length, 4);
chunks.write(subChunk1DataBytes);
chunks.write("data".getBytes());
writeLE(chunks, pcmData.length, 4);
chunks.write(pcmData);
fos.write("RIFF".getBytes());
byte chunkBytes[] = chunks.toByteArray();
writeLE(fos, 4 + chunkBytes.length, 4);
fos.write("WAVE".getBytes());
fos.write(chunkBytes);
//size1=>16bit*/
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException ex) {
//ignore
}
}
}
}
public void exportSounds(String outdir, List<Tag> tags, boolean mp3, boolean wave) throws IOException {
if (tags.isEmpty()) {
return;
}
@@ -677,9 +744,13 @@ public class SWF {
if (t instanceof DefineSoundTag) {
DefineSoundTag st = (DefineSoundTag) t;
if ((st.soundFormat == 2) && mp3) {
if ((st.soundFormat == DefineSoundTag.FORMAT_ADPCM) && wave) {
fos = new FileOutputStream(outdir + File.separator + id + ".wav");
createWavFromAdpcm(fos, st.soundRate, st.soundSize, st.soundType, st.soundData);
} else if ((st.soundFormat == DefineSoundTag.FORMAT_MP3) && mp3) {
fos = new FileOutputStream(outdir + File.separator + id + ".mp3");
fos.write(st.soundData);
fos.write(st.soundData, 2, st.soundData.length - 2);
} else {
fos = new FileOutputStream(outdir + File.separator + id + ".flv");
FLVOutputStream flv = new FLVOutputStream(fos);
@@ -692,11 +763,19 @@ public class SWF {
List<SoundStreamBlockTag> blocks = new ArrayList<SoundStreamBlockTag>();
List<Object> objs = new ArrayList<Object>(this.tags);
populateSoundStreamBlocks(objs, t, blocks);
if ((shead.getSoundFormat() == 2) && mp3) {
if ((shead.getSoundFormat() == DefineSoundTag.FORMAT_ADPCM) && wave) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
for (int b = 0; b < blocks.size(); b++) {
byte data[] = blocks.get(b).getData(SWF.DEFAULT_VERSION);
baos.write(data);
}
fos = new FileOutputStream(outdir + File.separator + id + ".wav");
createWavFromAdpcm(fos, shead.getSoundRate(), shead.getSoundSize(), shead.getSoundType(), baos.toByteArray());
} else if ((shead.getSoundFormat() == DefineSoundTag.FORMAT_MP3) && mp3) {
fos = new FileOutputStream(outdir + File.separator + id + ".mp3");
for (int b = 0; b < blocks.size(); b++) {
byte data[] = blocks.get(b).getData(SWF.DEFAULT_VERSION);
fos.write(data, 4, data.length - 4);
fos.write(data, 2, data.length - 2);
}
} else {
fos = new FileOutputStream(outdir + File.separator + id + ".flv");

View File

@@ -181,7 +181,7 @@ public class SWFInputStream extends InputStream {
return bytesRead;
}
private void alignByte() {
public void alignByte() {
bitPos = 0;
}
private int lastPercent = -1;
@@ -2974,4 +2974,11 @@ public class SWFInputStream extends InputStream {
public int available() throws IOException {
return is.available();
}
public long availableBits() throws IOException {
if (bitPos > 0) {
return available() * 8 + (8 - bitPos);
}
return available() * 8;
}
}

View File

@@ -22,7 +22,7 @@ public class ExportDialog extends JDialog {
{"Plain Text", "Formatted text"},
{"PNG/JPEG"},
{"FLV (No audio)"},
{"MP3/FLV", "FLV (Audio only)"},
{"MP3/WAV/FLV", "FLV (Audio only)"},
{"AS", "PCODE"}
};
String optionNames[] = {

View File

@@ -1292,7 +1292,7 @@ public class MainFrame extends JFrame implements ActionListener, TreeSelectionLi
final String selFile = Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath();
Configuration.setConfig("lastExportDir", Helper.fixDialogFile(chooser.getSelectedFile()).getParentFile().getAbsolutePath());
final boolean isPcode = export.getOption(ExportDialog.OPTION_ACTIONSCRIPT) == 1;
final boolean isMp3 = export.getOption(ExportDialog.OPTION_SOUNDS) == 0;
final boolean isMp3OrWav = export.getOption(ExportDialog.OPTION_SOUNDS) == 0;
final boolean isFormatted = export.getOption(ExportDialog.OPTION_TEXTS) == 1;
final boolean onlySel = e.getActionCommand().endsWith("SEL");
(new Thread() {
@@ -1352,7 +1352,7 @@ public class MainFrame extends JFrame implements ActionListener, TreeSelectionLi
SWF.exportShapes(selFile + File.separator + "shapes", shapes);
swf.exportTexts(selFile + File.separator + "texts", texts, isFormatted);
swf.exportMovies(selFile + File.separator + "movies", movies);
swf.exportSounds(selFile + File.separator + "sounds", sounds, isMp3);
swf.exportSounds(selFile + File.separator + "sounds", sounds, isMp3OrWav, isMp3OrWav);
swf.exportBinaryData(selFile + File.separator + "binaryData", binaryData);
if (abcPanel != null) {
for (int i = 0; i < tlsList.size(); i++) {
@@ -1375,7 +1375,7 @@ public class MainFrame extends JFrame implements ActionListener, TreeSelectionLi
swf.exportShapes(selFile + File.separator + "shapes");
swf.exportTexts(selFile + File.separator + "texts", isFormatted);
swf.exportMovies(selFile + File.separator + "movies");
swf.exportSounds(selFile + File.separator + "sounds", isMp3);
swf.exportSounds(selFile + File.separator + "sounds", isMp3OrWav, isMp3OrWav);
swf.exportBinaryData(selFile + File.separator + "binaryData");
swf.exportActionScript(selFile, isPcode);
}

View File

@@ -96,14 +96,12 @@ public class DefineSoundTag extends CharacterTag {
}
public String getExportFormat() {
if (soundFormat == FORMAT_MP3) {
if (soundFormat == DefineSoundTag.FORMAT_MP3) {
return "mp3";
}
if (soundFormat == DefineSoundTag.FORMAT_ADPCM) {
return "wav";
}
return "flv";
}
public double getkHz() {
double rateMap[] = {5.5, 11, 22, 44};
return rateMap[soundRate];
}
}

View File

@@ -17,10 +17,11 @@
package com.jpexs.decompiler.flash.tags;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.tags.base.RemoveTag;
import java.io.ByteArrayInputStream;
import java.io.IOException;
public class RemoveObject2Tag extends Tag {
public class RemoveObject2Tag extends Tag implements RemoveTag {
public int depth;
@@ -29,4 +30,9 @@ public class RemoveObject2Tag extends Tag {
SWFInputStream sis = new SWFInputStream(new ByteArrayInputStream(data), version);
depth = sis.readUI16();
}
@Override
public int getDepth() {
return depth;
}
}

View File

@@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash.tags;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.SWFOutputStream;
import com.jpexs.decompiler.flash.tags.base.RemoveTag;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -28,7 +29,7 @@ import java.io.OutputStream;
*
* @author JPEXS
*/
public class RemoveObjectTag extends Tag {
public class RemoveObjectTag extends Tag implements RemoveTag {
/**
* ID of character to place
@@ -71,4 +72,9 @@ public class RemoveObjectTag extends Tag {
characterId = sis.readUI16();
depth = sis.readUI16();
}
@Override
public int getDepth() {
return depth;
}
}

View File

@@ -18,7 +18,6 @@ package com.jpexs.decompiler.flash.tags;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.SWFOutputStream;
import static com.jpexs.decompiler.flash.tags.DefineSoundTag.FORMAT_MP3;
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -50,9 +49,12 @@ public class SoundStreamHead2Tag extends CharacterTag implements SoundStreamHead
@Override
public String getExportFormat() {
if (streamSoundCompression == FORMAT_MP3) {
if (streamSoundCompression == DefineSoundTag.FORMAT_MP3) {
return "mp3";
}
if (streamSoundCompression == DefineSoundTag.FORMAT_ADPCM) {
return "wav";
}
return "flv";
}

View File

@@ -18,7 +18,6 @@ package com.jpexs.decompiler.flash.tags;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.SWFOutputStream;
import static com.jpexs.decompiler.flash.tags.DefineSoundTag.FORMAT_MP3;
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -45,9 +44,12 @@ public class SoundStreamHeadTag extends CharacterTag implements SoundStreamHeadT
@Override
public String getExportFormat() {
if (streamSoundCompression == FORMAT_MP3) {
if (streamSoundCompression == DefineSoundTag.FORMAT_MP3) {
return "mp3";
}
if (streamSoundCompression == DefineSoundTag.FORMAT_ADPCM) {
return "wav";
}
return "flv";
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright (C) 2013 JPEXS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.jpexs.decompiler.flash.tags.base;
/**
*
* @author JPEXS
*/
public interface RemoveTag {
public int getDepth();
}

View File

@@ -0,0 +1,284 @@
/*
* Copyright (C) 2013 JPEXS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.jpexs.decompiler.flash.types.sound;
import com.jpexs.decompiler.flash.EndOfStreamException;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.SWFOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
*
* @author JPEXS
*/
public class AdpcmDecoder {
private static final int indexAdjustTable2bit[] = {
-1, 2,
-1, 2};
private static final int indexAdjustTable3bit[] = {
-1, -1, 2, 4,
-1, -1, 2, 4};
private static final int indexAdjustTable4bit[] = {
-1, -1, -1, -1, 2, 4, 6, 8,
-1, -1, -1, -1, 2, 4, 6, 8};
private static final int indexAdjustTable5bit[] = {
-1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 4, 6, 8, 10, 13, 16,
-1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 4, 6, 8, 10, 13, 16};
private static final int stepSizeTable[] = {
7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34,
37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143,
157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, 494,
544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552,
1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, 4026,
4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442,
11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623,
27086, 29794, 32767
};
private static class AdpcmState {
public int index;
public int sample;
};
private static int decode2bit(int deltaCode, AdpcmState state) {
assert (deltaCode == (deltaCode & 3));
int step = stepSizeTable[state.index];
int difference = step >> 1;
if ((deltaCode & 1) == 1) {
difference += step;
}
if ((deltaCode & 2) == 2) {
difference = -difference;
}
state.sample += difference;
if (state.sample > 32767) {
state.sample = 32767;
} else if (state.sample < -32768) {
state.sample = -32768;
}
state.index += indexAdjustTable2bit[deltaCode];
if (state.index < 0) {
state.index = 0;
} else if (state.index > 88) {
state.index = 88;
}
return state.sample;
}
private static int decode3bit(int deltaCode, AdpcmState state) {
assert (deltaCode == (deltaCode & 7));
int step = stepSizeTable[state.index];
int difference = step >> 2;
if ((deltaCode & 1) == 1) {
difference += step >> 1;
}
if ((deltaCode & 2) == 2) {
difference += step;
}
if ((deltaCode & 4) == 4) {
difference = -difference;
}
state.sample += difference;
if (state.sample > 32767) {
state.sample = 32767;
} else if (state.sample < -32768) {
state.sample = -32768;
}
state.index += indexAdjustTable3bit[deltaCode];
if (state.index < 0) {
state.index = 0;
} else if (state.index > 88) {
state.index = 88;
}
return state.sample;
}
private static int decode4bit(int deltaCode, AdpcmState state) {
assert (deltaCode == (deltaCode & 15));
int step = stepSizeTable[state.index];
int difference = step >> 3;
if ((deltaCode & 1) == 1) {
difference += step >> 2;
}
if ((deltaCode & 2) == 2) {
difference += step >> 1;
}
if ((deltaCode & 4) == 4) {
difference += step;
}
if ((deltaCode & 8) == 8) {
difference = -difference;
}
state.sample += difference;
if (state.sample > 32767) {
state.sample = 32767;
} else if (state.sample < -32768) {
state.sample = -32768;
}
state.index += indexAdjustTable4bit[deltaCode];
if (state.index < 0) {
state.index = 0;
} else if (state.index > 88) {
state.index = 88;
}
return state.sample;
}
private static int decode5bit(int deltaCode, AdpcmState state) {
assert (deltaCode >= 0);
assert (deltaCode <= 31 /* 2#11111 */);
int step = stepSizeTable[state.index];
int difference = step >> 4;
if ((deltaCode & 1) == 1) {
difference += step >> 3;
}
if ((deltaCode & 2) == 2) {
difference += step >> 2;
}
if ((deltaCode & 4) == 4) {
difference += step >> 1;
}
if ((deltaCode & 8) == 8) {
difference += step;
}
if ((deltaCode & 16) == 16) {
difference = -difference;
}
state.sample += difference;
if (state.sample > 32767) {
state.sample = 32767;
} else if (state.sample < -32768) {
state.sample = -32768;
}
state.index += indexAdjustTable5bit[deltaCode];
if (state.index < 0) {
state.index = 0;
} else if (state.index > 88) {
state.index = 88;
}
return state.sample;
}
public static byte[] decode(byte data[], boolean isStereo) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
decode(new ByteArrayInputStream(data), baos, isStereo);
return baos.toByteArray();
}
public static void decode(InputStream is, OutputStream os, boolean is_stereo) throws IOException {
int adpcm_code_size;
SWFInputStream sis = new SWFInputStream(is, SWF.DEFAULT_VERSION);
SWFOutputStream sos = new SWFOutputStream(os, SWF.DEFAULT_VERSION);
adpcm_code_size = (int) sis.readUB(2);
int bits_per_code = adpcm_code_size + 2;
try {
do {
if (is_stereo) {
int initialSampleLeft = (int) sis.readSB(16);
int initialIndexLeft = (int) sis.readUB(6);
int initialSampleRight = (int) sis.readSB(16);
int initialIndexRight = (int) sis.readUB(6);
AdpcmState stateLeft = new AdpcmState();
stateLeft.index = initialIndexLeft;
stateLeft.sample = initialSampleLeft;
AdpcmState stateRight = new AdpcmState();
stateRight.index = initialIndexRight;
stateRight.sample = initialSampleRight;
for (int i = 1; (i <= 4095) && (sis.availableBits() >= bits_per_code * 2); i++) {
int codeLeft = (int) sis.readUB(bits_per_code);
int codeRight = (int) sis.readUB(bits_per_code);
int valLeft = 0;
int valRight = 0;
switch (bits_per_code) {
case 2:
valLeft = decode2bit(codeLeft, stateLeft);
valRight = decode2bit(codeRight, stateRight);
break;
case 3:
valLeft = decode3bit(codeLeft, stateLeft);
valRight = decode3bit(codeRight, stateRight);
break;
case 4:
valLeft = decode4bit(codeLeft, stateLeft);
valRight = decode4bit(codeRight, stateRight);
break;
case 5:
valLeft = decode5bit(codeLeft, stateLeft);
valRight = decode5bit(codeRight, stateRight);
break;
}
sos.writeSI16(valLeft);
sos.writeSI16(valRight);
}
} else {
int initialSample = (int) sis.readSB(16);
int initialIndex = (int) sis.readUB(6);
AdpcmState state = new AdpcmState();
state.index = initialIndex;
state.sample = initialSample;
for (int i = 1; (i <= 4095) && (sis.availableBits() >= bits_per_code); i++) {
int code = (int) sis.readUB(bits_per_code);
int val = 0;
switch (bits_per_code) {
case 2:
val = decode2bit(code, state);
break;
case 3:
val = decode3bit(code, state);
break;
case 4:
val = decode4bit(code, state);
break;
case 5:
val = decode5bit(code, state);
break;
}
sos.writeSI16(val);
}
}
} while (sis.available() > 0);
} catch (EndOfStreamException eos) {
}
}
}

View File

@@ -48,6 +48,7 @@ import com.jpexs.decompiler.flash.tags.base.ButtonTag;
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
import com.jpexs.decompiler.flash.tags.base.FontTag;
import com.jpexs.decompiler.flash.tags.base.ImageTag;
import com.jpexs.decompiler.flash.tags.base.RemoveTag;
import com.jpexs.decompiler.flash.tags.base.ShapeTag;
import com.jpexs.decompiler.flash.tags.base.TextTag;
import com.jpexs.decompiler.flash.types.BUTTONCONDACTION;
@@ -605,7 +606,7 @@ public class XFLConverter {
for (Tag t : tags) {
if (t instanceof SoundStreamHeadTypeTag) {
SoundStreamHeadTypeTag ssh = (SoundStreamHeadTypeTag) t;
ssh.setVirtualCharacterId(maxId++);
ssh.setVirtualCharacterId(++maxId);
}
if (t instanceof CharacterTag) {
CharacterTag ct = (CharacterTag) t;
@@ -1149,7 +1150,7 @@ public class XFLConverter {
int soundSize = 0;
long soundSampleCount = 0;
byte soundData[] = new byte[0];
double rateMap[] = {5.5, 11, 22, 44};
int rateMap[] = {5, 11, 22, 44};
String exportFormat = "flv";
if (symbol instanceof SoundStreamHeadTypeTag) {
SoundStreamHeadTypeTag sstream = (SoundStreamHeadTypeTag) symbol;
@@ -1206,7 +1207,7 @@ public class XFLConverter {
}
if (soundFormat == DefineSoundTag.FORMAT_ADPCM) {
SWFInputStream sis = new SWFInputStream(new ByteArrayInputStream(soundData), SWF.DEFAULT_VERSION);
exportFormat = "wav";
try {
int adpcmCodeSize = (int) sis.readUB(2);
bits = 2 + adpcmCodeSize;
@@ -1278,7 +1279,7 @@ public class XFLConverter {
String symbolFile = "sound" + symbol.getCharacterID() + "." + exportFormat;
files.put(symbolFile, data);
String mediaLinkStr = "<DOMSoundItem name=\"" + symbolFile + "\" sourceLastImported=\"" + getTimestamp() + "\" externalFileSize=\"" + data.length + "\"";
mediaLinkStr += " href=\"" + symbolFile + "\"";
mediaLinkStr += " format=\"";
mediaLinkStr += rateMap[soundRate] + "kHz";
mediaLinkStr += " " + (soundSize == 1 ? "16bit" : "8bit");
@@ -1293,7 +1294,7 @@ public class XFLConverter {
mediaLinkStr += "/>\n";
media.add(mediaLinkStr);
}
//TODO: sound, video...
//TODO: video...
}
if (!media.isEmpty()) {
ret += "<media>";
@@ -1385,11 +1386,11 @@ public class XFLConverter {
ret += " soundLoop=\"" + startSound.soundInfo.loopCount + "\"";
}
if (!startSound.soundInfo.syncNoMultiple && !startSound.soundInfo.syncStop) {
//event
} else if (startSound.soundInfo.syncNoMultiple && !startSound.soundInfo.syncStop) {
if (startSound.soundInfo.syncStop) {
ret += " soundSync=\"stop\"";
} else if (startSound.soundInfo.syncNoMultiple) {
ret += " soundSync=\"start\"";
}
};
soundEnvelopeStr += "<SoundEnvelope>";
if (startSound.soundInfo.hasEnvelope) {
for (SOUNDENVELOPE env : startSound.soundInfo.envelopeRecords) {
@@ -1459,8 +1460,7 @@ public class XFLConverter {
String lastActionScript = "";
String frameName = null;
boolean isAnchor = false;
StartSoundTag startSound = null;
SoundStreamHeadTypeTag soundStreamHead = null;
for (Tag t : tags) {
if (t instanceof PlaceObjectTypeTag) {
PlaceObjectTypeTag po = (PlaceObjectTypeTag) t;
@@ -1482,41 +1482,6 @@ public class XFLConverter {
}
}
}
if (t instanceof StartSoundTag) {
if (startSound != null) {
lastActionScript = initActionScript + lastActionScript;
initActionScript = "";
ret += convertFrame(characters, tags, soundStreamHead, startSound, frame, frameName, isAnchor, duration, lastActionScript, lastElements);
frame += duration;
duration = 1;
lastElements = elements;
lastActionScript = actionScript;
elements = "";
actionScript = "";
frameName = null;
isAnchor = false;
soundStreamHead = null;
}
startSound = (StartSoundTag) t;
}
if (t instanceof SoundStreamHeadTypeTag) {
if (soundStreamHead != null) {
lastActionScript = initActionScript + lastActionScript;
initActionScript = "";
ret += convertFrame(characters, tags, soundStreamHead, startSound, frame, frameName, isAnchor, duration, lastActionScript, lastElements);
frame += duration;
duration = 1;
lastElements = elements;
lastActionScript = actionScript;
elements = "";
actionScript = "";
frameName = null;
isAnchor = false;
startSound = null;
soundStreamHead = null;
}
soundStreamHead = (SoundStreamHeadTypeTag) t;
}
if (t instanceof DoActionTag) {
actionScript += convertActionScript((DoActionTag) t);
}
@@ -1525,25 +1490,36 @@ public class XFLConverter {
if (frameName != null) {
lastActionScript = initActionScript + lastActionScript;
initActionScript = "";
ret += convertFrame(characters, tags, soundStreamHead, startSound, frame, frameName, isAnchor, duration, lastActionScript, lastElements);
ret += convertFrame(characters, tags, null, null, frame, frameName, isAnchor, duration, lastActionScript, lastElements);
frame += duration;
duration = 1;
lastElements = elements;
lastActionScript = actionScript;
elements = "";
actionScript = "";
startSound = null;
soundStreamHead = null;
}
frameName = flt.getLabelName();
isAnchor = flt.isNamedAnchor();
}
if (t instanceof RemoveTag) {
if (!lastElements.equals("") || !lastActionScript.equals("")) {
lastActionScript = initActionScript + lastActionScript;
initActionScript = "";
ret += convertFrame(characters, tags, null, null, frame, frameName, isAnchor, duration, lastActionScript, lastElements);
}
frame += duration;
duration = 1;
lastElements = elements;
lastActionScript = actionScript;
elements = "";
actionScript = "";
}
if (t instanceof ShowFrameTag) {
if (!elements.equals("") || !actionScript.equals("") || soundStreamHead != null || startSound != null) {
if (!elements.equals("") || !actionScript.equals("")) {
if (!lastElements.equals("") || !lastActionScript.equals("")) {
lastActionScript = initActionScript + lastActionScript;
initActionScript = "";
ret += convertFrame(characters, tags, soundStreamHead, startSound, frame, frameName, isAnchor, duration, lastActionScript, lastElements);
ret += convertFrame(characters, tags, null, null, frame, frameName, isAnchor, duration, lastActionScript, lastElements);
}
frame += duration;
duration = 1;
@@ -1551,8 +1527,6 @@ public class XFLConverter {
lastActionScript = actionScript;
elements = "";
actionScript = "";
soundStreamHead = null;
startSound = null;
} else {
duration++;
}
@@ -1560,12 +1534,12 @@ public class XFLConverter {
}
lastActionScript = initActionScript + lastActionScript;
initActionScript = "";
if (!lastElements.equals("") || !lastActionScript.equals("") || soundStreamHead != null || startSound != null) {
if (!lastElements.equals("") || !lastActionScript.equals("")) {
if (frame < 0) {
frame = 0;
duration = 1;
}
ret += convertFrame(characters, tags, soundStreamHead, startSound, frame, frameName, isAnchor, duration, lastActionScript, lastElements);
ret += convertFrame(characters, tags, null, null, frame, frameName, isAnchor, duration, lastActionScript, lastElements);
}
afterStr = "</frames>" + afterStr;
@@ -1575,6 +1549,52 @@ public class XFLConverter {
return ret;
}
public static String convertSoundLayer(int layerIndex, String backgroundColor, HashMap<Integer, CharacterTag> characters, List<Tag> tags) {
String ret = "";
StartSoundTag lastStartSound = null;
SoundStreamHeadTypeTag lastSoundStreamHead = null;
StartSoundTag startSound = null;
SoundStreamHeadTypeTag soundStreamHead = null;
int duration = 1;
int frame = 0;
for (Tag t : tags) {
if (t instanceof StartSoundTag) {
startSound = (StartSoundTag) t;
}
if (t instanceof SoundStreamHeadTypeTag) {
soundStreamHead = (SoundStreamHeadTypeTag) t;
}
if (t instanceof ShowFrameTag) {
if (soundStreamHead != null || startSound != null) {
if (lastSoundStreamHead != null || lastStartSound != null) {
ret += convertFrame(characters, tags, lastSoundStreamHead, lastStartSound, frame, null, false, duration, "", "");
}
frame += duration;
duration = 1;
lastSoundStreamHead = soundStreamHead;
lastStartSound = startSound;
soundStreamHead = null;
startSound = null;
} else {
duration++;
}
}
}
if (lastSoundStreamHead != null || lastStartSound != null) {
if (frame < 0) {
frame = 0;
duration = 1;
}
ret += convertFrame(characters, tags, lastSoundStreamHead, lastStartSound, frame, null, false, duration, "", "");
}
if (!ret.equals("")) {
ret = "<DOMLayer name=\"Layer " + layerIndex + "\" color=\"" + backgroundColor + "\">"
+ "<frames>" + ret + "</frames>"
+ "</DOMLayer>";
}
return ret;
}
public static String convertTimeline(String initActionScript, List<Integer> oneInstanceShapes, String backgroundColor, List<Tag> tags, HashMap<Integer, CharacterTag> characters, String name) {
String ret = "";
ret += "<DOMTimeline name=\"" + name + "\">";
@@ -1657,6 +1677,10 @@ public class XFLConverter {
}
int soundLayerIndex = layerCount;
ret += convertSoundLayer(soundLayerIndex, backgroundColor, characters, tags);
ret += "</layers>";
ret += "</DOMTimeline>";
return ret;