Permalink
Browse files

Adds DefineSound and StreamSoundBlock tags parsing

  • Loading branch information...
yurydelendik committed Dec 31, 2012
1 parent 5f89caa commit 883262f2ae685583d77f0d66a10c30dd4a8b12e2
@@ -32,6 +32,7 @@
<script src="../../src/swf/image.js"></script>
<script src="../../src/swf/label.js"></script>
<script src="../../src/swf/shape.js"></script>
+ <script src="../../src/swf/sound.js"></script>
<script src="../../src/swf/text.js"></script>
<!-- Load AVM1 Dependencies -->
@@ -49,6 +49,7 @@
<script src="../../src/swf/image.js"></script>
<script src="../../src/swf/label.js"></script>
<script src="../../src/swf/shape.js"></script>
+ <script src="../../src/swf/sound.js"></script>
<script src="../../src/swf/text.js"></script>
<!-- Load AVM1 Dependencies -->
@@ -30,6 +30,7 @@
<script src="../swf/image.js"></script>
<script src="../swf/label.js"></script>
<script src="../swf/shape.js"></script>
+ <script src="../swf/sound.js"></script>
<script src="../swf/text.js"></script>
<!-- Load AVM1 Dependencies -->
@@ -22,6 +22,7 @@ var LoaderDefinition = (function () {
'../../swf/image.js',
'../../swf/label.js',
'../../swf/shape.js',
+ '../../swf/sound.js',
'../../swf/text.js'
];
@@ -78,10 +79,7 @@ var LoaderDefinition = (function () {
symbol = defineShape(swfTag, symbols);
break;
case SWF_TAG_CODE_DEFINE_SOUND:
- symbol = {
- type: 'sound',
- id: swfTag.id
- };
+ symbol = defineSound(swfTag, symbols);
break;
case SWF_TAG_CODE_DEFINE_SPRITE:
var depths = { };
@@ -160,6 +158,7 @@ var LoaderDefinition = (function () {
var frame = { type: 'frame' };
var symbols = this._symbols;
var tagsProcessed = 0;
+ var soundStream = null;
return {
onstart: function(result) {
@@ -201,6 +200,19 @@ var LoaderDefinition = (function () {
}
initActionBlocks[tag.spriteId] = tag.actionsData;
break;
+ case SWF_TAG_CODE_START_SOUND:
+ var startSounds = frame.startSounds;
+ if (!startSounds)
+ frame.startSounds = startSounds = [];
+ startSounds.push(tag);
+ break;
+ case SWF_TAG_CODE_SOUND_STREAM_HEAD:
+ soundStream = createSoundStream(tag);
+ frame.soundStream = soundStream.info;
+ break;
+ case SWF_TAG_CODE_SOUND_STREAM_BLOCK:
+ frame.soundStream = soundStream.decode(tag.data);
+ break;
case SWF_TAG_CODE_EXPORT_ASSETS:
case SWF_TAG_CODE_SYMBOL_CLASS:
var exports = frame.exports;
@@ -661,8 +673,27 @@ var LoaderDefinition = (function () {
});
break;
case 'sound':
+ var audio = new Audio;
+ if (symbol.packaged) {
+ var audioPromise = new Promise;
+ audio.onload = function () {
+ audioPromise.resolve();
+ };
+ var a = "";
+ for (var i = 0; i < symbol.packaged.data.length; i++)
+ a += String.fromCharCode(symbol.packaged.data[i]);
+ audio.src = 'data:' + symbol.packaged.mimeType + ';base64,' + btoa(a);
+
+ promiseQueue.push(audioPromise);
+ }
+
symbolInfo.className = 'flash.media.Sound';
- symbolInfo.props = { };
+ symbolInfo.props = {
+ audio: audio,
+ sampleRate: symbol.sampleRate,
+ channels: symbol.channels,
+ pcm: symbol.pcm
+ };
break;
case 'sprite':
var frameCount = symbol.frameCount;
View
@@ -15,10 +15,10 @@ var tagHandler = {
/* DoAction */ 12: DO_ACTION,
/* DefineFontInfo */ 13: undefined,
/* DefineSound */ 14: DEFINE_SOUND,
- /* StartSound */ 15: undefined,
+ /* StartSound */ 15: START_SOUND,
/* DefineButtonSound */ 17: undefined,
- /* SoundStreamHead */ 18: undefined,
- /* SoundStreamBlock */ 19: undefined,
+ /* SoundStreamHead */ 18: SOUND_STREAM_HEAD,
+ /* SoundStreamBlock */ 19: SOUND_STREAM_BLOCK,
/* DefineBitsLossless */ 20: DEFINE_BITMAP,
/* DefineBitsJPEG2 */ 21: DEFINE_IMAGE,
/* DefineShape2 */ 22: DEFINE_SHAPE,
@@ -34,7 +34,7 @@ var tagHandler = {
/* DefineEditText */ 37: DEFINE_TEXT,
/* DefineSprite */ 39: undefined,
/* FrameLabel */ 43: FRAME_LABEL,
- /* SoundStreamHead2 */ 45: undefined,
+ /* SoundStreamHead2 */ 45: SOUND_STREAM_HEAD,
/* DefineMorphShape */ 46: DEFINE_SHAPE,
/* DefineFont2 */ 48: DEFINE_FONT2,
/* ExportAssets */ 56: SYMBOL_CLASS,
@@ -62,7 +62,7 @@ var tagHandler = {
/* DefineSceneAndFrameLabelData */ 86: undefined,
/* DefineBinaryData */ 87: undefined,
/* DefineFontName */ 88: undefined,
- /* StartSound2 */ 89: undefined,
+ /* StartSound2 */ 89: START_SOUND,
/* DefineBitsJPEG4 */ 90: DEFINE_IMAGE,
/* DefineFont4 */ 91: undefined
};
View
@@ -0,0 +1,209 @@
+/* -*- mode: javascript; tab-width: 4; indent-tabs-mode: nil -*- */
+
+var SOUND_SIZE_8_BIT = 0;
+var SOUND_SIZE_16_BIT = 1;
+var SOUND_TYPE_MONO = 0;
+var SOUND_TYPE_STEREO = 1;
+
+var SOUND_FORMAT_PCM_BE = 0;
+var SOUND_FORMAT_ADPCM = 1;
+var SOUND_FORMAT_MP3 = 2;
+var SOUND_FORMAT_PCM_LE = 3;
+var SOUND_FORMAT_NELLYMOSER_16 = 4;
+var SOUND_FORMAT_NELLYMOSER_8 = 5;
+var SOUND_FORMAT_NELLYMOSER = 6;
+var SOUND_FORMAT_SPEEX = 11;
+
+var SOUND_RATES = [5512, 11250, 22500, 44100];
+
+function defineSound(tag, dictionary) {
+ var channels = tag.soundType == SOUND_TYPE_STEREO ? 2 : 1;
+ var samplesCount = tag.samplesCount;
+ var sampleRate = SOUND_RATES[tag.soundRate];
+
+ var pcm = new Float32Array(samplesCount * channels);
+ var data = tag.soundData;
+ var packaged;
+ switch (tag.soundFormat) {
+ case SOUND_FORMAT_PCM_BE:
+ if (tag.soundSize == SOUND_SIZE_16_BIT) {
+ for (var i = 0, j = 0; i < pcm.length; i++, j += 2)
+ pcm[i] = ((data[j] << 8) | data[j + 1]) / 32768;
+ } else {
+ for (var i = 0; i < pcm.length; i++)
+ pcm[i] = (data[i] - 128) / 128;
+ }
+ break;
+ case SOUND_FORMAT_PCM_LE:
+ if (tag.soundSize == SOUND_SIZE_16_BIT) {
+ for (var i = 0, j = 0; i < pcm.length; i++, j += 2)
+ pcm[i] = ((data[j + 1] << 8) | data[j]) / 32768;
+ } else {
+ for (var i = 0; i < pcm.length; i++)
+ pcm[i] = (data[i] - 128) / 128;
+ }
+ break;
+ case SOUND_FORMAT_MP3:
+ if (typeof MP3Decoder !== 'undefined') {
+ var decoder = new MP3Decoder();
+ var i = 0;
+ decoder.onframedata = function (frameData) {
+ for (var j = 0; j < frameData.length; j++)
+ pcm[i++] = frameData[j];
+ };
+ decoder.push(data);
+ break;
+ } else {
+ packaged = {
+ data: data.subarray(2),
+ mimeType: 'audio/mpeg'
+ };
+ break;
+ }
+ default:
+ error('Unsupported audio format: ' + tag.soundFormat);
+ //for (var i = 0; i < pcm.length; i++)
+ // pcm[i] = Math.sin(i / sampleRate * 220);
+ break;
+ }
+
+ var sound = {
+ type: 'sound',
+ id: tag.id,
+ sampleRate: sampleRate,
+ channels: channels,
+ pcm: pcm
+ };
+ if (packaged)
+ sound.packaged = packaged;
+ return sound;
+}
+
+var nextSoundStreamId = 0;
+
+function SwfSoundStream(samplesCount, sampleRate, channels) {
+ this.streamId = (nextSoundStreamId++);
+ this.samplesCount = samplesCount;
+ this.sampleRate = sampleRate;
+ this.channels = channels;
+ this.currentSample = 0;
+}
+SwfSoundStream.prototype = {
+ get info() {
+ return {
+ samplesCount: this.samplesCount,
+ sampleRate: this.sampleRate,
+ channels: this.channels,
+ streamId: this.streamId
+ };
+ },
+ decode: function (data) {
+ throw 'SwfSoundStream.decode: not implemented';
+ }
+};
+
+function SwfSoundStream_decode_PCM(data) {
+ var pcm = new Float32Array(data.length);
+ for (var i = 0; i < pcm.length; i++)
+ pcm[i] = (data[i] - 128) / 128;
+ this.currentSample += pcm.length / this.channels;
+ return {
+ pcm: pcm,
+ streamId: this.streamId
+ };
+}
+
+function SwfSoundStream_decode_PCM_be(data) {
+ var pcm = new Float32Array(data.length / 2);
+ for (var i = 0, j = 0; i < pcm.length; i++, j += 2)
+ pcm[i] = ((data[i] << 8) | data[i + 1]) / 128;
+ this.currentSample += pcm.length / this.channels;
+ return {
+ pcm: pcm,
+ streamId: this.streamId
+ };
+}
+
+function SwfSoundStream_decode_PCM_le(data) {
+ var pcm = new Float32Array(data.length / 2);
+ for (var i = 0, j = 0; i < pcm.length; i++, j += 2)
+ pcm[i] = ((data[j + 1] << 8) | data[j]) / 128;
+ this.currentSample += pcm.length / this.channels;
+ return {
+ pcm: pcm,
+ streamId: this.streamId
+ };
+}
+
+function SwfSoundStream_decode_MP3(data) {
+ var samplesCount = (data[1] << 8) | data[0];
+ var seek = (data[3] << 8) | data[2];
+ var pcm = new Float32Array(samplesCount * this.channels);
+ var i = 0;
+ var decoder = this.mp3Decoder;
+ decoder.onframedata = function (frameData) {
+ for (var j = 0; j < frameData.length; j++)
+ pcm[i++] = frameData[j];
+ };
+ decoder.push(data.substring(4));
+ this.currentSample += samplesCount;
+ return {
+ pcm: pcm,
+ streamId: this.streamId,
+ seek: seek
+ };
+}
+
+function SwfSoundStream_decode_MP3_fake(data) {
+ var samplesCount = (data[1] << 8) | data[0];
+ var seek = (data[3] << 8) | data[2];
+ var pcm = new Float32Array(samplesCount * this.channels);
+ var sampleRate = this.sampleRate;
+ for (var i = 0; i < pcm.length; i++)
+ pcm[i] = Math.sin(i / sampleRate * 220);
+ this.currentSample += samplesCount;
+ return {
+ pcm: pcm,
+ streamId: this.streamId,
+ seek: seek
+ };
+}
+
+function createSoundStream(tag) {
+ var channels = tag.streamType == SOUND_TYPE_STEREO ? 2 : 1;
+ var samplesCount = tag.samplesCount;
+ var sampleRate = SOUND_RATES[tag.streamRate];
+ debugger;
+ var stream = new SwfSoundStream(samplesCount, sampleRate, channels);
+
+ switch (tag.streamCompression) {
+ case SOUND_FORMAT_PCM_BE:
+ if (tag.soundSize == SOUND_SIZE_16_BIT) {
+ stream.decode = SwfSoundStream_decode_PCM_be;
+ } else {
+ stream.decode = SwfSoundStream_decode_PCM;
+ }
+ break;
+ case SOUND_FORMAT_PCM_LE:
+ if (tag.soundSize == SOUND_SIZE_16_BIT) {
+ stream.decode = SwfSoundStream_decode_PCM_le;
+ } else {
+ stream.decode = SwfSoundStream_decode_PCM;
+ }
+ break;
+ case SOUND_FORMAT_MP3:
+ if (typeof MP3Decoder !== 'undefined') {
+ stream.decode = SwfSoundStream_decode_MP3;
+ stream.mp3Decoder = new MP3Decoder();
+ break;
+ } else {
+ stream.decode = SwfSoundStream_decode_MP3_fake;
+ break;
+ }
+ default:
+ error('Unsupported audio format: ' + tag.soundFormat);
+ break;
+ }
+
+ return stream;
+}
View
@@ -440,13 +440,12 @@ var TEXT_RECORD = {
}
}]]
};
-var ENVELOPE = {
- pos: UI32,
+var SOUND_ENVELOPE = {
+ pos44: UI32,
volumeLeft: UI16,
volumeRight: UI16
};
var SOUND_INFO = {
- soundId: UI16,
$$reserved: UB(2),
stop: UB(1),
noMultiple: UB(1),
@@ -455,12 +454,12 @@ var SOUND_INFO = {
$hasOutPoint: UB(1),
$hasInPoint: UB(1),
inPoint: ['hasInPoint', [UI32]],
- outPoint: ['hasInPoint', [UI32]],
- loopCount: ['hasLoopCount', [UI16]],
+ outPoint: ['hasOutPoint', [UI32]],
+ loopCount: ['hasLoops', [UI16]],
$0: ['hasEnvelope', [{
$envelopeCount: UI8,
envelopes: {
- $: ENVELOPE,
+ $: SOUND_ENVELOPE,
count: 'envelopeCount'
}
}]]
Oops, something went wrong.

0 comments on commit 883262f

Please sign in to comment.