A movie has two kinds of sound. Event sounds are characters, defined once with DefineSound and started by StartSound or a button. Streaming sound belongs to a timeline: a SoundStreamHead gives its format and each frame carries its share in a SoundStreamBlock, so the sound stays in step with the frames. In a ZWS movie these tags are in the decompressed data; the sound data inside them is in its own coding.
DefineSound (14)
| Type | Name | Description |
|---|---|---|
| UI16 | SoundId | The character ID |
| UB[4] | SoundFormat | The coding: table below |
| UB[2] | SoundRate | 0 5.5 kHz, 1 11 kHz, 2 22 kHz, 3 44 kHz (5,512, 11,025, 22,050 and 44,100 Hz) |
| UB[1] | SoundSize | 0 8-bit, 1 16-bit; always 1 for compressed formats |
| UB[1] | SoundType | 0 mono, 1 stereo |
| UI32 | SoundSampleCount | Samples a channel |
| bytes | SoundData | To the end of the tag. For MP3: SI16 SeekSamples, then MP3 frames |
Sound formats
| SoundFormat | Coding | From SWF |
|---|---|---|
| 0 | Uncompressed, in the byte order of the machine that wrote the file | 1 |
| 1 | ADPCM | 1 |
| 2 | MP3 | 4 |
| 3 | Uncompressed, little-endian | 4 |
| 4 | Nellymoser 16 kHz | 10 |
| 5 | Nellymoser 8 kHz | 10 |
| 6 | Nellymoser | 6 |
| 11 | Speex | 10 |
8-bit uncompressed samples are unsigned, 16-bit ones signed. Format 0 is ambiguous for 16-bit data, so the specification says to use format 3; the explorer reads format 0 as little-endian, an assumption. The explorer plays uncompressed and ADPCM sounds, describes MP3 frame by frame from the frame headers, and does not decode Nellymoser or Speex.
StartSound (15)
| Type | Name | Description |
|---|---|---|
| UI16 | SoundId | The DefineSound to play |
| SOUNDINFO | SoundInfo | How to play it |
StartSound2 (89)
| Type | Name | Description |
|---|---|---|
| STRING | SoundClassName | The ActionScript 3 class of the sound |
| SOUNDINFO | SoundInfo | How to play it |
SWF 9.
SOUNDINFO
| Type | Name | Description |
|---|---|---|
| UB[2] | Reserved | 0 |
| UB[1] | SyncStop | Stop the sound instead of starting it (0x20) |
| UB[1] | SyncNoMultiple | Do not start it again if it is already playing (0x10) |
| UB[1] | HasEnvelope | (0x08) |
| UB[1] | HasLoops | (0x04) |
| UB[1] | HasOutPoint | (0x02) |
| UB[1] | HasInPoint | (0x01) |
| UI32 | InPoint | If HasInPoint: where to start, in 44 kHz samples |
| UI32 | OutPoint | If HasOutPoint: where to stop, in 44 kHz samples |
| UI16 | LoopCount | If HasLoops |
| UI8 | EnvPoints | If HasEnvelope |
| SOUNDENVELOPE × EnvPoints | EnvelopeRecords | Each UI32 Pos44 (in 44 kHz samples), UI16 LeftLevel and UI16 RightLevel (0 to 32,768) |
SoundStreamHead (18)
| Type | Name | Description |
|---|---|---|
| UB[4] | Reserved | 0 |
| UB[2] | PlaybackSoundRate | The rate to play at, as SoundRate |
| UB[1] | PlaybackSoundSize | 0 8-bit, 1 16-bit |
| UB[1] | PlaybackSoundType | 0 mono, 1 stereo |
| UB[4] | StreamSoundCompression | The coding, as SoundFormat: ADPCM or (from SWF 4) MP3 in this tag |
| UB[2] | StreamSoundRate | The rate of the data |
| UB[1] | StreamSoundSize | Always 1 for compressed data |
| UB[1] | StreamSoundType | 0 mono, 1 stereo |
| UI16 | StreamSoundSampleCount | The average samples a frame |
| SI16 | LatencySeek | MP3 only |
SoundStreamHead2 (45)
SWF 3. The same fields as SoundStreamHead, allowing any sound format.
SoundStreamBlock (19)
One frame’s share of the stream, to the end of the tag: ADPCM data with its own header in each block, uncompressed samples, or for MP3 a UI16 SampleCount, an SI16 SeekSamples, then MP3 frames.
MP3 in SWF
MP3 data is a run of MPEG audio layer III frames, MPEG-1, 2 or 2.5. In DefineSound it is MP3SOUNDDATA: SI16 SeekSamples, then the frames. In a SoundStreamBlock it is MP3STREAMSOUNDDATA: UI16 SampleCount, SI16 SeekSamples, then the frames. The explorer walks the frame headers to count frames, samples (1,152 a frame for MPEG-1, 576 for MPEG-2 and 2.5) and the duration, but does not decode them. The two layouts have not been checked against the specification’s text.
ADPCM
Flash’s ADPCM is a form of IMA ADPCM with 2- to 5-bit codes. The data is read as bits, most significant first, with no byte alignment between packets:
- UB[2] AdpcmCodeSize: the bits in each code, minus 2 (0 is 2 bits, 3 is 5 bits).
- Packets of 4,096 samples a channel; the last may be shorter. Each packet starts, for each channel (left first), with SB[16] InitialSample and UB[6] InitialIndex. InitialSample is the packet’s first sample.
- Then 4,095 codes a channel, interleaved left, right, left … for stereo.
In streaming sound each SoundStreamBlock holds a whole ADPCM data block, with its own AdpcmCodeSize. To decode one code of bits bits, for a channel with sample p and step index i:
- step = STEPS[i].
- diff = 0. For each magnitude bit, from the highest (worth 2bits − 2) down: if it is set, diff += step; then step = step >> 1. After the last, diff += step. This is (magnitude + ½) × step ÷ 2bits − 2, in integers.
- If the sign bit (worth 2bits − 1) is set, p −= diff, otherwise p += diff. Hold p between −32,768 and 32,767.
- i += INDEX[bits][magnitude], held between 0 and 88.
- Output p.
| Code size | Index change by magnitude |
|---|---|
| 2 bits | −1, 2 |
| 3 bits | −1, −1, 2, 4 |
| 4 bits | −1, −1, −1, −1, 2, 4, 6, 8 |
| 5 bits | −1, −1, −1, −1, −1, −1, −1, −1, 1, 2, 4, 6, 8, 10, 13, 16 |
STEPS is the standard IMA ADPCM step table of 89 entries: 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.
This follows FFmpeg’s SWF ADPCM decoder, which follows the specification’s “ADPCM compression” section. The explorer’s decoder works this way and decodes every ADPCM sound in the movies examined for this site.