mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-05-31 09:17:21 +00:00
Fixed: Flash viewer - Sound envelope handling
This commit is contained in:
@@ -144,8 +144,11 @@ import com.jpexs.decompiler.flash.types.ColorTransform;
|
||||
import com.jpexs.decompiler.flash.types.MATRIX;
|
||||
import com.jpexs.decompiler.flash.types.RECT;
|
||||
import com.jpexs.decompiler.flash.types.SHAPE;
|
||||
import com.jpexs.decompiler.flash.types.SOUNDENVELOPE;
|
||||
import com.jpexs.decompiler.flash.types.SOUNDINFO;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Internal;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFField;
|
||||
import com.jpexs.decompiler.flash.types.sound.SoundInfoSoundCacheEntry;
|
||||
import com.jpexs.decompiler.flash.xfl.FLAVersion;
|
||||
import com.jpexs.decompiler.flash.xfl.XFLConverter;
|
||||
import com.jpexs.decompiler.flash.xfl.XFLExportSettings;
|
||||
@@ -341,7 +344,7 @@ public final class SWF implements SWFContainerItem, Timelined {
|
||||
private final Cache<SHAPE, ShapeExportData> shapeExportDataCache = Cache.getInstance(true, true, "shapeExportData");
|
||||
|
||||
@Internal
|
||||
private final Cache<SoundTag, byte[]> soundCache = Cache.getInstance(false, false, "sound");
|
||||
private final Cache<SoundInfoSoundCacheEntry, byte[]> soundCache = Cache.getInstance(false, false, "sound");
|
||||
|
||||
@Internal
|
||||
public final AS2Cache as2Cache = new AS2Cache();
|
||||
@@ -2577,9 +2580,10 @@ public final class SWF implements SWFContainerItem, Timelined {
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte[] getFromCache(SoundTag soundTag) {
|
||||
if (soundCache.contains(soundTag)) {
|
||||
return soundCache.get(soundTag);
|
||||
public byte[] getFromCache(SOUNDINFO soundInfo, SoundTag soundTag) {
|
||||
SoundInfoSoundCacheEntry key = new SoundInfoSoundCacheEntry(soundInfo, soundTag);
|
||||
if (soundCache.contains(key)) {
|
||||
return soundCache.get(key);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -2590,8 +2594,9 @@ public final class SWF implements SWFContainerItem, Timelined {
|
||||
}
|
||||
}
|
||||
|
||||
public void putToCache(SoundTag soundTag, byte[] data) {
|
||||
soundCache.put(soundTag, data);
|
||||
public void putToCache(SOUNDINFO soundInfo, SoundTag soundTag, byte[] data) {
|
||||
SoundInfoSoundCacheEntry key = new SoundInfoSoundCacheEntry(soundInfo, soundTag);
|
||||
soundCache.put(key, data);
|
||||
}
|
||||
|
||||
public void clearImageCache() {
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.exporters;
|
||||
|
||||
import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler;
|
||||
@@ -156,7 +157,7 @@ public class SoundExporter {
|
||||
}
|
||||
} else {
|
||||
List<ByteArrayRange> soundData = st.getRawSoundData();
|
||||
List<ByteArrayRange> soundData = st.getRawSoundData();
|
||||
fmt.createWav(null, soundData, fos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.types;
|
||||
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
@@ -32,4 +33,38 @@ public class SOUNDENVELOPE implements Serializable {
|
||||
|
||||
@SWFType(BasicType.UI16)
|
||||
public int rightLevel;
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 7;
|
||||
hash = 29 * hash + (int) (this.pos44 ^ (this.pos44 >>> 32));
|
||||
hash = 29 * hash + this.leftLevel;
|
||||
hash = 29 * hash + this.rightLevel;
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final SOUNDENVELOPE other = (SOUNDENVELOPE) obj;
|
||||
if (this.pos44 != other.pos44) {
|
||||
return false;
|
||||
}
|
||||
if (this.leftLevel != other.leftLevel) {
|
||||
return false;
|
||||
}
|
||||
if (this.rightLevel != other.rightLevel) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,13 +12,15 @@
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.types;
|
||||
|
||||
import com.jpexs.decompiler.flash.types.annotations.Conditional;
|
||||
import com.jpexs.decompiler.flash.types.annotations.Reserved;
|
||||
import com.jpexs.decompiler.flash.types.annotations.SWFType;
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -56,4 +58,70 @@ public class SOUNDINFO implements Serializable {
|
||||
|
||||
@Conditional("hasEnvelope")
|
||||
public SOUNDENVELOPE[] envelopeRecords = new SOUNDENVELOPE[0];
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 3;
|
||||
hash = 17 * hash + this.reserved;
|
||||
hash = 17 * hash + (this.syncStop ? 1 : 0);
|
||||
hash = 17 * hash + (this.syncNoMultiple ? 1 : 0);
|
||||
hash = 17 * hash + (this.hasEnvelope ? 1 : 0);
|
||||
hash = 17 * hash + (this.hasLoops ? 1 : 0);
|
||||
hash = 17 * hash + (this.hasOutPoint ? 1 : 0);
|
||||
hash = 17 * hash + (this.hasInPoint ? 1 : 0);
|
||||
hash = 17 * hash + (int) (this.inPoint ^ (this.inPoint >>> 32));
|
||||
hash = 17 * hash + (int) (this.outPoint ^ (this.outPoint >>> 32));
|
||||
hash = 17 * hash + this.loopCount;
|
||||
hash = 17 * hash + Arrays.deepHashCode(this.envelopeRecords);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final SOUNDINFO other = (SOUNDINFO) obj;
|
||||
if (this.reserved != other.reserved) {
|
||||
return false;
|
||||
}
|
||||
if (this.syncStop != other.syncStop) {
|
||||
return false;
|
||||
}
|
||||
if (this.syncNoMultiple != other.syncNoMultiple) {
|
||||
return false;
|
||||
}
|
||||
if (this.hasEnvelope != other.hasEnvelope) {
|
||||
return false;
|
||||
}
|
||||
if (this.hasLoops != other.hasLoops) {
|
||||
return false;
|
||||
}
|
||||
if (this.hasOutPoint != other.hasOutPoint) {
|
||||
return false;
|
||||
}
|
||||
if (this.hasInPoint != other.hasInPoint) {
|
||||
return false;
|
||||
}
|
||||
if (this.inPoint != other.inPoint) {
|
||||
return false;
|
||||
}
|
||||
if (this.outPoint != other.outPoint) {
|
||||
return false;
|
||||
}
|
||||
if (this.loopCount != other.loopCount) {
|
||||
return false;
|
||||
}
|
||||
if (!Arrays.deepEquals(this.envelopeRecords, other.envelopeRecords)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,10 +12,12 @@
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.types.sound;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.types.SOUNDINFO;
|
||||
import com.jpexs.helpers.ByteArrayRange;
|
||||
import com.jpexs.helpers.utf8.Utf8Helper;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
@@ -198,7 +200,7 @@ public class SoundFormat {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean createWav(SOUNDINFO soundInfo, List<ByteArrayRange> dataRanges, OutputStream os) throws IOException {
|
||||
ensureFormat();
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
SoundDecoder decoder = getDecoder();
|
||||
@@ -208,8 +210,56 @@ public class SoundFormat {
|
||||
decoder.decode(sis, baos);
|
||||
}
|
||||
|
||||
/*
|
||||
System.err.println("sampling rate:" + samplingRate);
|
||||
System.err.println("len:" + baos.toByteArray().length);
|
||||
*/
|
||||
boolean convertedStereo = stereo;
|
||||
|
||||
ByteArrayOutputStream baosFiltered;
|
||||
if (soundInfo == null) {
|
||||
baosFiltered = baos;
|
||||
} else {
|
||||
int inPoint = (soundInfo.hasInPoint ? (int) Math.round(soundInfo.inPoint * samplingRate / 44100.0) : 0);
|
||||
int outPoint = (soundInfo.hasOutPoint ? (int) Math.round(soundInfo.outPoint * samplingRate / 44100.0) : Integer.MAX_VALUE);
|
||||
byte data[] = baos.toByteArray();
|
||||
baosFiltered = new ByteArrayOutputStream();
|
||||
int inPointBytes = inPoint * 2 /*16bit*/ * (stereo ? 2 : 1);
|
||||
int outPointBytes = soundInfo.hasOutPoint ? outPoint * 2 /*16bit*/ * (stereo ? 2 : 1) : data.length;
|
||||
for (int i = inPointBytes; i < outPointBytes; i += (stereo ? 4 : 2)) {
|
||||
int left = ((data[i] & 0xff) + ((data[i + 1] & 0xff) << 8)) << 16 >> 16;
|
||||
int right = left;
|
||||
if (stereo) {
|
||||
right = ((data[i + 2] & 0xff) + ((data[i + 3] & 0xff) << 8)) << 16 >> 16;
|
||||
}
|
||||
|
||||
if (soundInfo.hasEnvelope) {
|
||||
for (int e = 0; e < soundInfo.envelopeRecords.length - 1; e++) {
|
||||
int envPosBytes = inPointBytes + (int) (soundInfo.envelopeRecords[e].pos44 * samplingRate / 44100.0 * 2 * (stereo ? 2 : 1));
|
||||
int envNextPosBytes = inPointBytes + (int) (soundInfo.envelopeRecords[e + 1].pos44 * samplingRate / 44100.0 * 2 * (stereo ? 2 : 1));
|
||||
if (i >= envPosBytes && i <= envNextPosBytes) {
|
||||
double pos = (i - envPosBytes) / (double) (envNextPosBytes - envPosBytes);
|
||||
|
||||
int leftLevel = (int) (soundInfo.envelopeRecords[e].leftLevel + (soundInfo.envelopeRecords[e + 1].leftLevel - soundInfo.envelopeRecords[e].leftLevel) * pos);
|
||||
int rightLevel = (int) (soundInfo.envelopeRecords[e].rightLevel + (soundInfo.envelopeRecords[e + 1].rightLevel - soundInfo.envelopeRecords[e].rightLevel) * pos);
|
||||
double leftMultiplier = leftLevel / 32768.0;
|
||||
double rightMultiplier = rightLevel / 32768.0;
|
||||
|
||||
left = (int) Math.round(left * leftMultiplier);
|
||||
right = (int) Math.round(right * rightMultiplier);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
writeLE(baosFiltered, left, 2);
|
||||
writeLE(baosFiltered, right, 2);
|
||||
}
|
||||
convertedStereo = true;
|
||||
}
|
||||
|
||||
try {
|
||||
try {
|
||||
createWavFromPcmData(os, samplingRate, true, convertedStereo, baosFiltered.toByteArray());
|
||||
return true;
|
||||
} catch (IOException ex) {
|
||||
return false;
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.jpexs.decompiler.flash.types.sound;
|
||||
|
||||
import com.jpexs.decompiler.flash.tags.base.SoundTag;
|
||||
import com.jpexs.decompiler.flash.types.SOUNDINFO;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class SoundInfoSoundCacheEntry {
|
||||
public SOUNDINFO soundInfo;
|
||||
public SoundTag soundTag;
|
||||
|
||||
public SoundInfoSoundCacheEntry(SOUNDINFO soundInfo, SoundTag soundTag) {
|
||||
this.soundInfo = soundInfo;
|
||||
this.soundTag = soundTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 7;
|
||||
hash = 47 * hash + Objects.hashCode(this.soundInfo);
|
||||
hash = 47 * hash + Objects.hashCode(this.soundTag);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final SoundInfoSoundCacheEntry other = (SoundInfoSoundCacheEntry) obj;
|
||||
if (!Objects.equals(this.soundInfo, other.soundInfo)) {
|
||||
return false;
|
||||
}
|
||||
if (!Objects.equals(this.soundTag, other.soundTag)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user