mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-07-17 13:48:13 +00:00
FLA export - sounds
Wav export (for ADPCM sounds)
This commit is contained in:
@@ -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());
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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[] = {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user