Wednesday, October 01, 2008

Let’s build an MP3-decoder!

Even though MP3 is probably the single most well known file format and codec on Earth, it’s not very well understood by most programmers – for many encoders/decoders is in the class of software “other people” write, like standard libraries or operating system kernels. This article will attempt to demystify the decoder, with short top-down primers on signal processing and information theory when necessary. Additionally, a small but not full-featured decoder will be written (in Haskell), suited to play around with.

The focus on this article is on concepts and the design choices the MPEG team made when they designed the codec – not on uninteresting implementation details or heavy theory. Some parts of a decoder are quite arcane and are better understood by reading the specification, a good book on signal processing, or the many papers on MP3 (see references at the end).

A note on the code: The decoder accompanying this article is written for readability, not speed. Additionally, some unusual features have been left out. The end result is a decoder that is inefficient and not standards compliant, but with hopefully readable code. You can grab the source here: mp3decoder-0.0.1.tar.gz. Scroll down to the bottom of the article or see README for build instructions.

A fair warning: The author is a hobby programmer, not an authority in signal processing. If you find an error, please drop me an e-mail.

With that out of the way, we begin our journey with the ear.

Human hearing and psychoacoustics

The main idea of MP3 encoding, and lossy audio coding in general, is removing acoustically irrelevant information from an audio signal to reduce its size. The job of the encoder is to remove some or all information from a signal component, while at the same time not changing the signal in such a way audible artifacts are introduced.

Several properties (or “deficiencies”) of human hearing are used by lossy audio codecs. One basic property is we can’t hear above 20 kHz or below 20 Hz, approximately. Additionally, there’s a threshold of hearing – once a signal is below a certain threshold it can’t be heard, it’s too quiet. This threshold varies with frequency; a 20 Hz tone can only be heard if it’s stronger than around 60 decibels, while frequencies in the region 1-5 kHz can easily be perceived at low volume.

A very important property affecting the auditory system is known as masking. A loud signal will “mask” other signals sufficiently close in frequency or time; meaning the loud signal modifies the threshold of hearing for spectral and temporal neighbors. This property is very useful: not only can the nearby masked signals be removed; the audible signal can also be compressed further as the noise introduced by heavy compression will be masked too.

This masking phenomenon happens within frequency regions known as critical bands – a strong signal within a critical band will mask frequencies within the band. We can think of the ear as a set of band pass filters, where different parts of the ear pick up different frequency regions. An audiologist or acoustics professor have plenty to say about critical bands and the subtleties of masking effects, however in this article we are taking a simplified engineering approach: for our purpose it’s enough to think of these critical bands as fixed frequency regions where masking effects occur.

Using the properties of the human auditory system, lossy codecs and encoders remove inaudible signals to reduce the information content, thus compressing the signal. The MP3 standard does not dictate how an encoder should be written (though it assumes the existence of critical bands), and implementers have plenty of freedom to remove content they deem imperceptible. One encoder may decide a particular frequency is inaudible and should be removed, while another encoder keeps the same signal. Different encoders use different psychoacoustic models, models describing how humans perceive sounds and thus what information may be removed.

About MP3

Before we begin decoding MP3, it is necessary to understand exactly what MP3 is. MP3 is a codec formally known as MPEG-1 Audio Layer 3, and it is defined in the MPEG-1 standard. This standard defines three different audio codecs, where layer 1 is the simplest that has the worst compression ratio, and layer 3 is the most complex but has the highest compression ratio and the best audio quality per bit rate. Layer 3 is based on layer 2, in turn based on layer 1. All of the three codecs share similarities and have many encoding/decoding parts in common.

The rationale for this design choice made sense back when the MPEG-1 standard was first written, as the similarities between the three codecs would ease the job for implementers. In hindsight, building layer 3 on top of the other two layers was perhaps not the best idea. Many of the advanced features of MP3 are shoehorned into place, and are more complex than they would have been if the codec was designed from scratch. In fact, many of the features of AAC were designed to be “simpler” than the counterpart in MP3.

At a very high level, an MP3 encoder works like this: An input source, say a WAV file, is fed to the encoder. There the signal is split into parts (in the time domain), to be processed individually. The encoder then takes one of the short signals and transforms it to the frequency domain. The psychoacoustic model removes as much information as possible, based on the content and phenomena such as masking. The frequency samples, now with less information, are compressed in a generic lossless compression step. The samples, as well as parameters how the samples were compressed, are then written to disk in a binary file format.

The decoder works in reverse. It reads the binary file format, decompress the frequency samples, reconstructs the samples based on information how content was removed by the model, and then transforms them to the time domain. Let’s start with the binary file format.

Decoding, step 1: Making sense of the data

Many computer users know that an MP3 are made up of several “frames”, consecutive blocks of data. While important for unpacking the bit stream, frames are not fundamental and cannot be decoded individually. In this article, what is usually called a frame we call a physical frame, while we call a block of data that can actually be decoded a logical frame, or simply just a frame.

A logical frame has many parts: it has a 4 byte header easily distinguishable from other data in the bit stream, it has 17 or 32 bytes known as side information, and a few hundred bytes of main data.

A physical frame has a header, an optional 2 byte checksum, side information, but only some of the main data unless in very rare circumstances. The screenshot below shows a physical frame as a thick black border, the frame header as 4 red bytes, and the side information as blue bytes (this MP3 does not have the optional checksum). The grayed out bytes is the main data that corresponds to the highlighted header and side information. The header for the following physical frame is also highlighted, to show the header always begin at offset 0.

The absolutely first thing we do when we decode the MP3 is to unpack the physical frames to logical frames – this is a means of abstraction, once we have a logical frame we can forget about everything else in the bit stream. We do this by reading an offset value in the side information that point to the beginning of the main data.

Why’s not the main data for a logical frame kept within the physical frame? At first this seems unnecessarily clumsy, but it has some advantages. The length of a physical frame is constant (within a byte) and solely based on the bit rate and other values stored in the easily found header. This makes seeking to arbitrary frames in the MP3 efficient for media players. Additionally, as frames are not limited to a fixed size in bits, parts of the audio signal with complex sounds can use bytes from preceding frames, in essence giving all MP3:s variable bit rate.

There are some limitations though: a frame can save its main data in several preceding frames, but not following frames – this would make streaming difficult. Also, the main data for a frame cannot be arbitrarily large, and is limited to about 500 bytes. This is limit is fairly short, and is often criticized.

The perceptive reader may notice the gray main data bytes in the image above begin with an interesting pattern (3E 50 00 00…) that resembles the first bytes of the main data in the next logical frame (38 40 00 00…). There is some structure in the main data, but usually this won’t be noticeable in a hex editor.

To work with the bit stream, we are going to use a very simple type:

data MP3Bitstream = MP3Bitstream {
    bitstreamStream :: B.ByteString,
    bitstreamBuffer :: [Word8]

Where the ByteString is the unparsed bit stream, and the [Word8] is an internal buffer used to reconstruct logical frames from physical frames. Not familiar with Haskell? Don’t worry; all the code in this article is only complementary.

As the bit stream may contain data we consider garbage, such as ID3 tags, we are using a simple helper function, mp3Seek, which takes the MP3Bitstream and discards bytes until it finds a valid header. The new MP3Bitstream can then be passed to a function that does the actual physical to logical unpacking.

mp3Seek :: MP3Bitstream -> Maybe MP3Bitstream
mp3UnpackFrame :: MP3Bitstream -> (MP3Bitstream, Maybe MP3LogicalFrame)

The anatomy of a logical frame

When we’re done decoding proper, a logical frame will have yielded us exactly 1152 time domain samples per channel. In a typical PCM WAV file, storing these samples would require 2304 bytes per channel – more than 4½ KB in total for a typical audio track. While large parts of the compression from 4½ KB audio to 0.4 KB frame stems from the removal of frequency content, a not insignificant contribution is thanks to a very efficient binary representation.

Before that, we have to make sense of the logical frame, especially the side information and the main data. When we’re done parsing the logical frame, we will have compressed audio and a bunch of parameters describing how to decompress it.

Unpacking the logical frame requires some information about the different parts. The 4-byte header stores some properties about the audio signal, most importantly the sample rate and the channel mode (mono, stereo etc). The information in the header is useful both for media player software, and for decoding the audio. Note that the header does not store many parameters used by the decoder, e.g. how audio samples should be reconstructed, those parameters are stored elsewhere.

The side information is 17 bytes for mono, 32 bytes otherwise. There’s lots of information in the side info. Most of the bits describe how the main data should be parsed, but there are also some parameters saved here used by other parts of the decoder.

The main data contains two “chunks” per channel, which are blocks of compressed audio (and corresponding parameters) decoded individually. A mono frame has two chunks, while a stereo frame has four. This partitioning is cruft left over from layer 1 and 2. Most new audio codecs designed from scratch don’t bother with this partitioning.

The first few bits of a chunk are the so-called scale factors – basically 21 numbers, which are used for decoding the chunk later. The reason the scale factors are stored in the main data and not the side information, as many other parameters, is the scale factors take up quite a lot of space. How the scale factors should be parsed, for example how long a scale factor is in bits, is described in the side information.

Following the scale factors is the actual compressed audio data for this chunk. These are a few hundred numbers, and take up most of the space in a chunk. These audio samples are actually compressed in a sense many programmers may be familiar with: Huffman coding, as used by zip, zlib and other common lossless data compression methods.

The Huffman coding is actually one of the biggest reasons an MP3 file is so small compared to the raw audio, and it’s worth investigating further. For now let’s pretend we have decoded the main data completely, including the Huffman coded data. Once we have done this for all four chunks (or two chunks for mono), we have successfully unpacked the frame. The function that does this is:

mp3ParseMainData :: MP3LogicalFrame -> Maybe MP3Data

Where MP3Data store some information, and the two/four parsed chunks.

Huffman coding

The basic idea of Huffman coding is simple. We take some data we want to compress, say a list of 8 bit characters. We then create a value table where we order the characters by frequency. If we don’t know beforehand how our list of characters will look, we can order the characters by probability of occurring in the string. We then assign code words to the value table, where we assign the short code words to the most probable values. A code word is simply an n-bit integer designed in such a way there are no ambiguities or clashes with shorter code words.

For example, lets say we have a very long string made up of the letters A, C, G and T. Being good programmers, we notice it’s wasteful to save this string as 8 bit characters, so we store them with 2 bits each. Huffman coding can compress the string further, if some of the letters are more frequent than others. In our example, we know beforehand ‘A’ occurs in the string with about 40% probability. We create a frequency table:


We then assign code words to the table. This is done in a specific way – if we pick code words at random we are not Huffman coding anymore but using a generic variable-length code.


Say we have a string of one thousand characters. If we save this string in ASCII, it will take up 8000 bits. If we instead use our 2-bit representation, it will only take 2000 bits. With Huffman coding however, we can save it in only 1850.

Decoding is the reverse of coding. If we have a bit string, say 00011111010, we read bits until there’s a match in the table. Our example string decodes to AAATGC. Note that the code word table is designed so there are no conflicts. If the table read


… and we encounter the bit 0 in a table, there’s no way we can ever get a C as the A will match all the time.

The standard method of decoding a Huffman coded string is by walking a binary tree, created from the code word table. When we encounter a 0 bit, we move – say – left in the tree, and right when we see a 1. This is the simplest method used in our decoder.

There’s a more efficient method to decode the string, a basic time-space tradeoff that can be used when the same code word table is used to code/decode several different bit strings, as is the case with MP3. Instead of walking a tree, we use a lookup table in a clever way. This is best illustrated with an example:

lookup[0xx] = (A, 1)
lookup[10x] = (C, 2)
lookup[110] = (G, 3)
lookup[111] = (T, 3)

In the table above, xx means all permutations of 2 bits; all bit patterns from 00 to 11. Our table thus contains all indices from 000 to 111. To decode a string using this table we peek 3 bits in the coded bit string. Our example bit string is 00011111010, so our index is 000. This matches the pair (A, 1), which means we have found the value A and we should discard 1 bit from the input. We peek another 3 bits in the string, and repeat the process.

For very large Huffman tables, where the longest code word is dozens of bits, it is not feasible to create a lookup table using this method of padding as it would require a table approximately 2n elements large, where n is the length of the longest code word. By carefully looking at a code word table however, it’s often possible to craft a very efficient lookup table by hand, that uses a method with “pointers” to different tables, which handle the longest code words.

How Huffman coding is used in MP3

To understand how Huffman coding is used by MP3, it is necessary to understand exactly what is being coded or decoded. The compressed data that we are about to decompress is frequency domain samples. Each logical frame has up to four chunks – two per channel – each containing up to 576 frequency samples. For a 44100 Hz audio signal, the first frequency sample (index 0) represent frequencies at around 0 Hz, while the last sample (index 575) represent a frequency around 22050 Hz.

These samples are divided into five different regions of variable length. The first three regions are known as the big values regions, the fourth region is known as the count1 region (or quad region), and the fifth is known as the zero region. The samples in the zero region are all zero, so these are not actually Huffman coded. If the big values regions and the quad region decode to 400 samples, the remaining 176 are simply padded with 0.

The three big values regions represent the important lower frequencies in the audio. The name big values refer to the information content: when we are done decoding the regions will contain integers in the range –8206 to 8206.

These three big values regions are coded with three different Huffman tables, defined in the MP3 standard. The standard defines 15 large tables for these regions, where each table outputs two frequency samples for a given code word. The tables are designed to compress the “typical” content of the frequency regions as much as possible.

To further increase compression, the 15 tables are paired with another parameter for a total of 29 different ways each of the three regions can be compressed. The side information contains information which of the 29 possibilities to use. Somewhat confusingly, the standard calls these possibilities “tables”. We will call them table pairs instead.

As an example, here is Huffman code table 1 (table1), as defined in the standard:

Code wordValue
1(0, 0)
001(0, 1)
01(1, 0)
000(1, 1)

And here is table pair 1: (table1, 0).

To decode a big values region using table pair 1, we proceed as follows: Say the chunk contains the following bits: 000101010... First we decode the bits as we usually decode Huffman coded strings: The three bits 000 correspond to the two output samples 1 and 1, we call them x and y.

Here’s where it gets interesting: The largest code table defined in the standard has samples no larger than 15. This is enough to represent most signals satisfactory, but sometimes a larger value is required. The second value in the table pair is known as the linbits (for some reason), and whenever we have found an output sample that is the maximum value (15) we read linbits number of bits, and add them to the sample. For table pair 1, the linbits is 0, and the maximum sample value is never 15, so we ignore it in this case. For some samples, linbits may be as large as 13, so the maximum value is 15+8191.

When we have read linbits for sample x, we get the sign. If x is not 0, we read one bit. This determines of the sample is positive or negative.

All in all, the two samples are decoded in these steps:

  1. Decode the first bits using the Huffman table. Call the samples x and y.
  2. If x = 15 and linbits is not 0, get linbits bits and add to x. x is now at most 8206.
  3. If x is not 0, get one bit. If 1, then x is –x.
  4. Do step 2 and 3 for y.

The count1 region codes the frequencies that are so high they have been compressed tightly, and when decoded we have samples in the range –1 to 1. There are only two possible tables for this region; these are known as the quad tables as each code word corresponds to 4 output samples. There are no linbits for the count1 region, so decoding is only a matter of using the appropriate table and get the sign bits.

  1. Decode the first bits using the Huffman table. Call the samples v, w, x and y.
  2. If v is not 0, get one bit. If 1, then v is –v.
  3. Do step 2 for w, x and y.

Step 1, summary

Unpacking an MP3 bit stream is very tedious, and is without doubt the decoding step that requires the most lines of code. The Huffman tables alone are a good 70 kilobytes, and all the parsing and unpacking requires a few hundred lines of code too.

The Huffman coding is undoubtedly one of the most important features of MP3 though. For a 500-byte logical frame with two channels, the output is 4x576 samples (1152 per channel) with a range of almost 15 bits, and that is even before we’ve done any transformations on the output samples. Without the Huffman coding, a logical frame would require up to 4-4½ kilobytes of storage, about an eight-fold increase in size.

All the unpacking is done by Unpack.hs, which exports two functions, mp3Seek and mp3Unpack. The latter is a simple helper function that combines mp3UnpackFrame and mp3ParseMainData. It looks like this:

mp3Unpack :: MP3Bitstream -> (MP3Bitstream, Maybe MP3Data)

Decoding, step 2: Re-quantization

Having successfully unpacked a frame, we now have a data structure containing audio to be processed further, and parameters how this should be done. Here are our types, what we got from mp3Unpack:

data MP3Data = MP3Data1Channels SampleRate ChannelMode (Bool, Bool) 
                                MP3DataChunk MP3DataChunk
             | MP3Data2Channels SampleRate ChannelMode (Bool, Bool) 
                                MP3DataChunk MP3DataChunk 
                                MP3DataChunk MP3DataChunk

data MP3DataChunk = MP3DataChunk {
    chunkBlockType    :: Int,
    chunkBlockFlag    :: BlockFlag,
    chunkScaleGain    :: Double,
    chunkScaleSubGain :: (Double, Double, Double),
    chunkScaleLong    :: [Double],
    chunkScaleShort   :: [[Double]],
    chunkISParam      :: ([Int], [[Int]]),
    chunkData         :: [Int]

MP3Data is simply an unpacked and parsed logical frame. It contains some useful information, first is the sample rate, second is the channel mode, third are the stereo modes (more about them later). Then are the two-four data chunks, decoded separately. What the values stored in an MP3DataChunk represent will be described soon. For now it’s enough to know chunkData store the (at most) 576 frequency domain samples. An MP3DataChunk is also known as a granule, however to avoid confusion we are not going to use this term until later in the article.


We have already done one of the key steps of decoding an MP3: decoding the Huffman data. We will now do the second key step – re-quantization.

As hinted in the chapter on human hearing, the heart of MP3 compression is quantization. Quantization is simply the approximation of a large range of values with a smaller set of values i.e. using fewer bits. For example if you take an analog audio signal and sample it at discrete intervals of time you get a discrete signal – a list of samples. As the analog signal is continuous, these samples will be real values. If we quantize the samples, say approximate each real valued sample with an integer between –32767 and +32767, we end up with a digital signal – discrete in both dimensions.

Quantization can be used as a form of lossy compression. For 16 bit PCM each sample in the signal can take on one of 216 values. If we instead approximate each sample in the range –16383 to +16383, we lose information but save 1 bit per sample. The difference between the original value and the quantized value is known as the quantization error, and this results in noise. The difference between a real valued sample and a 16-bit sample is so small it’s inaudible for most purposes, but if we remove too much information from the sample, the difference between the original will soon be audible.

Let’s stop for a moment and think about where this noise comes from. This requires a mathematical insight, due to Fourier: all continuous signals can be created by adding sinusoids together – even the square wave! This means that if we take a pure sine wave, say at 440 Hz, and quantize it, the quantization error will manifest itself as new frequency components in the signal. This makes sense – the quantized sine is not really a pure sine, so there must be something else in the signal. These new frequencies will be all over the spectra, and is noise. If the quantization error is small, the magnitude of the noise will be small.

And this is where we can thank evolution our ear is not perfect: If there’s a strong signal within a critical band, the noise due to quantization errors will be masked, up to the threshold. The encoder can thus throw away as much information as possible from the samples within the critical band, up to the point were discarding more information would result in noise passing the audible threshold. This is the key insight of lossy audio encoding.

Quantization methods can be written as mathematical expressions. Say we have a real valued sample in the range –1 to 1. To quantize this value to a form suitable for a 16 bit WAV file, we multiply the sample with 32727 and throw away the fractional part: q = floor(s * 32767) or equivalently in a form many programmers are familiar with: (short)(s * 32767.0). Re-quantization in this simple case is a division, where the difference between the re-quantized sample and the original is the quantization error.

Re-quantization in MP3

After we unpacked the MP3 bit stream and Huffman decoded the frequency samples in a chunk, we ended up with quantized frequency samples between –8206 and 8206. Now it’s time to re-quantize these samples to real values (floats), like when we take a 16-bit PCM sample and turn it to a float. When we’re done we have a sample in the range –1 to 1, much smaller than 8206. However our new sample has a much higher resolution, thanks to the information the encoder left in the frame how the sample should be reconstructed.

The MP3 encoder uses a non-linear quantizer, meaning the difference between consecutive re-quantized values is not constant. This is because low amplitude signals are more sensitive to noise, and thus require more bits than stronger signals – think of it as using more bits for small values, and fewer bits for large values. To achieve this non-linearity, the different scaling quantities are non-linear.

The encoder will first raise all samples by 3/4, that is newsample = oldsample3/4. The purpose is, according to the literature, to make the signal-to-noise ratio more consistent. We will gloss over the why’s and how’s here, and just raise all samples by 4/3 to restore the samples to their original value.

All 576 samples are then scaled by a quantity simply known as the gain, or the global gain because all samples are affected. This is chunkScaleGain, and it’s also a non-linear value.

This far, we haven’t done anything really unusual. We have taken a value, at most 8206, and scaled it with a variable quantity. This is not that much different from a 16 bit PCM WAV, where we take a value, at most 32767, and scale it with the fixed quantity 1/32767. Now things will get more interesting.

Some frequency regions, partitioned into several scale factor bands, are further scaled individually. This is what the scale factors are for: the frequencies in the first scale factor band are all multiplied by the first scale factor, etc. The bands are designed to approximate the critical bands. Here’s an illustration of the scale factor bandwidths for a 44100 Hz MP3. The astute reader may notice there are 22 bands, but only 21 scale factors. This is a design limitation that affects the very high frequencies.

The reason these bands are scaled individually is to better control quantization noise. If there’s a strong signal in one band, it will mask the noise in this band but not others. The values within a scale factor band are thus quantized independently from other bands by the encoder, depending on the masking effects.

Because of reasons that will hopefully be made more clear shortly, a chunk can be scaled in three different ways.

For one type of chunk – called “long” – we scale the 576 frequencies by the global gain and the 21 scale factors (chunkScaleLong), and leave it at that.

For another type of chunk – called “short” – the 576 samples are really three interleaved sets of 192 frequency samples. Don’t worry if this doesn’t make any sense now, we will talk about it soon. In this case, the scale factor bands look slightly different than in the illustration above, to accommodate the reduced bandwidths of the scale factor bands. Also, the scale factors are not 21 numbers, but sets of three numbers (chunkScaleShort). An additional parameter, chunkScaleSubGain, further scales the individual three sets of samples.

The third type of chunk is a mix of the above two.

When we have multiplied each sample with the corresponding scale factor and other gains, we are left with a high precision floating point representation of the frequency domain, where each sample is in the range –1 to 1.

Here’s some code, that uses almost all values in a MP3DataChunk. The three different scaling methods are controlled by the BlockFlag. There will be plenty more information about the block flag later in this article.

mp3Requantize :: SampleRate -> MP3DataChunk -> [Frequency]
mp3Requantize samplerate (MP3DataChunk bt bf gain (sg0, sg1, sg2) 
                         longsf shortsf _ compressed)
    | bf == LongBlocks  = long
    | bf == ShortBlocks = short
    | bf == MixedBlocks = take 36 long ++ drop 36 short
        long  = zipWith procLong  compressed longbands
        short = zipWith procShort compressed shortbands

        procLong sample sfb = 
            let localgain   = longsf !! sfb
                dsample     = fromIntegral sample
            in gain * localgain * dsample **^ (4/3)

        procShort sample (sfb, win) =
            let localgain = (shortsf !! sfb) !! win
                blockgain = case win of 0 -> sg0
                                        1 -> sg1
                                        2 -> sg2
                dsample   = fromIntegral sample
            in gain * localgain * blockgain * dsample **^ (4/3)
        -- Frequency index (0-575) to scale factor band index (0-21).
        longbands = tableScaleBandIndexLong samplerate
        -- Frequency index to scale factor band index and window index (0-2).
        shortbands = tableScaleBandIndexShort samplerate

A fair warning: This presentation of the MP3 re-quantization step differs somewhat from the official specification. The specification presents the quantization as a long formula based on integer quantities. This decoder instead treats these integer quantities as floating point representations of non-linear quantities, so the re-quantization can be expressed as an intuitive series of multiplications. The end result is the same, but the intention is hopefully clearer.

Minor step: Reordering

Before quantizing the frequency samples, the encoder will in certain cases reorder the samples in a predefined way. We have already encountered this above: after the reordering by the encoder the “short” chunks with three small chunks of 192 samples each are combined to 576 samples ordered by frequency (sort of). This is to improve the efficiency of the Huffman coding, as the method with big values and different tables assume the lower frequencies are first in the list.

When we’re done re-quantizing in our decoder, we will reorder the “short” samples back to their original position. After this reordering, the samples in these chunks are no longer ordered by frequency. This is slightly confusing, so unless you are really interested in MP3 you can ignore this and concentrate on the “long” chunks, which have very few surprises.

Decoding, step 3: Joint Stereo

MP3 supports four different channel modes. Mono means the audio has a single channel. Stereo means the audio has two channels. Dual channel is identical to stereo for decoding purposes – it’s intended as information for the media player in case the two channels contain different audio, such as an audio book in two languages.

Then there’s joint stereo. This is like the regular stereo mode, but with some extra compression steps taking similarities between the two channels into account. This makes sense, especially for stereo music where there’s usually a very high correlation between the two channels. By removing some redundancy, the audio quality can be much higher for a given bit rate.

MP3 supports two joint stereo modes known as middle/side stereo (MS) and intensity stereo (IS). Whether these modes are in use is given by the (Bool, Bool) tuple in the MP3Data type. Additionally chunkISParam stores parameter used by IS mode.

MS stereo is very simple: instead of encoding two similar channels verbatim, the encoder computes the sum and the difference of the two channels before encoding. The information content in the “side” channel (difference) will be less than the “middle” channel (sum), and the encoder can use more bits for the middle channel for a better result. MS stereo is lossless, and is a very common mode that’s often used in joint stereo MP3:s. Decoding MS stereo is very cute:

mp3StereoMS :: [Frequency] -> [Frequency] -> ([Frequency], [Frequency])
mp3StereoMS middle side =
    let sqrtinv = 1 / (sqrt 2)
        left  = zipWith0 (\x y -> (x+y)*sqrtinv) 0.0 middle side
        right = zipWith0 (\x y -> (x-y)*sqrtinv) 0.0 middle side
    in (left, right)

The only oddity here is the division by the square root of 2 instead of simply 2. This is to scale down the channels for more efficient quantization by the encoder.

A more unusual stereo mode is known as intensity stereo, or IS for short. We will ignore IS stereo in this article.

Having done the stereo decoding, the only thing remaining is taking the frequency samples back to the time domain. This is the part heavy on theory.

Decoding, step 4: Frequency to time

At this point the only remaining MP3DataChunk values we will use are chunkBlockFlag and chunkBlockType. These are the sole two parameters that dictate how we’re going to transform our frequency domain samples to the time domain. To understand the block flag and block type we have to familiarize ourselves with some transforms, as well as one part of the encoder.

The encoder: filter banks and transforms

The input to an encoder is probably a time domain PCM WAV file, as one usually gets when ripping an audio CD. The encoder takes 576 time samples, from here on called a granule, and encodes two of these granules to a frame. For an input source with two channels, two granules per channel are stored in the frame. The encoder also saves information how the audio was compressed in the frame. This is the MP3Data type in our decoder.

The time domain samples are transformed to the frequency domain in several steps, one granule a time.

Analysis filter bank

First the 576 samples are fed to a set of 32 band pass filters, where each band pass filter outputs 18 time domain samples representing 1/32:th of the frequency spectra of the input signal. If the sample rate is 44100 Hz each band will be approximately 689 Hz wide (22050/32 Hz). Note that there’s downsampling going on here: Common band pass filters will output 576 output samples for 576 input samples, however the MP3 filters also reduce the number of samples by 32, so the combined output of all 32 filters is the same as the number of inputs.

This part of the encoder is known as the analysis filter bank (throw in the word polyphase for good measure), and it’s a part of the encoder common to all the MPEG-1 layers. Our decoder will do the reverse at the very end of the decoding process, combining the subbands to the original signal. The reverse is known as the synthesis filter bank. These two filter banks are simple conceptually, but real mammoths mathematically – at least the synthesis filter bank. We will treat them as black boxes.


The output of each band pass filter is further transformed by the MDCT, the modified discrete cosine transform. This transform is just a method of transforming the time domain samples to the frequency domain. Layer 1 and 2 does not use this MDCT, but it was added on top of the filter bank for layer 3 as a finer frequency resolution than 689 Hz (given 44.1 KHz sample rate) proved to give better compression. This makes sense: simply dividing the whole frequency spectra in fixed size blocks means the decoder has to take several critical bands into account when quantizing the signal, which results in a worse compression ratio.

The MDCT takes a signal and represents it as a sum of cosine waves, turning it to the frequency domain. Compared to the DFT/FFT and other well-known transforms, the MDCT has a few properties that make it very suited for audio compression.

First of all, the MDCT has the energy compaction property common to several of the other discrete cosine transforms. This means most of the information in the signal is concentrated to a few output samples with high energy. If you take an input sequence, do an (M)DCT transform on it, set the “small” output values to 0, then do the inverse transform – the result is a fairly small change in the original input. This property is of course very useful for compression, and thus different cosine transforms are used by not only MP3 and audio compression in general but also JPEG and video coding techniques.

Secondly, the MDCT is designed to be performed on consecutive blocks of data, so it has smaller discrepancies at block boundaries compared to other transforms. This also makes it very suited for audio, as we’re almost always working with really long signals.

Technically, the MDCT is a so-called lapped transform, which means we use input samples from the previous input data when we work with the current input data. The input is 2N time samples and the output is N frequency samples. Instead of transforming 2N length blocks separately, consecutive blocks are overlapped. This overlapping helps reducing artifacts at block boundaries. First we perform the MDCT on say samples 0-35 (inclusive), then 18-53, then 36-71… To smoothen the boundaries between consecutive blocks, the MDCT is usually combined with a windowing function that is performed prior to the transform. A windowing function is simply a sequence of values that are zero outside some region, and often between 0 and 1 within the region, that are to be multiplied with another sequence. For the MDCT smooth, arc-like window functions are usually used, which makes the boundaries of the input block go smoothly to zero at the edges.

In the case of MP3, the MDCT is done on the subbands from the analysis filter bank. In order to get all the nice properties of the MDCT, the transform is not done on the 18 samples directly, but on a windowed signal formed by the concatenation of the 18 previous and the current samples. This is illustrated in the picture below, showing two consecutive granules (MP3DataChunk) in an audio channel. Remember: we are looking at the encoder here, the decoder works in reverse. This illustration shows the MDCT of the 0-679 Hz band.

The MDCT can either be applied to the 36 samples as described above, or three MDCT:s are done on 12 samples each – in either case the output is 18 frequency samples. The first choice, known as the long method, gives us greater frequency resolution. The second choice, known as the short method, gives us greater time resolution. The encoder selects the long MDCT to get better audio quality when the signal changes very little, and it selects short when there’s lots going on, that is for transients.

For the whole granule of 576 samples, the encoder can either do the long MDCT on all 32 subbands – this is the long block mode, or it can do the short MDCT in all subbands – this is the short block mode. There’s a third choice, known as the mixed block mode. In this case the encoder uses the long MDCT on the first two subbands, and the short MDCT on the remaining. The mixed block mode is a compromise: it’s used when time resolution is necessary, but using the short block mode would result in artifacts. The lowest frequencies are thus treated as long blocks, where the ear is most sensitive to frequency inaccuracies. Notice that the boundaries of the mixed block mode is fixed: the first two, and only two, subbands use the long MDCT. This is considered a design limitation of MP3: sometimes it’d be useful to have high frequency resolution in more than two subbands. In practice, many encoders do not support mixed blocks.

We discussed the block modes briefly in the chapter on re-quantization and reordering, and hopefully that part will make a little more sense knowing what’s going on inside the encoder. The 576 samples in a short granule are really 3x 192 small granules, but stored in such a way the facilities for compressing a long granule can be used.

The combination of the analysis filter bank and the MDCT is known as the hybrid filter bank, and it’s a very confusing part of the decoder. The analysis filter bank is used by all MPEG-1 layers, but as the frequency bands does not reflect the critical bands, layer 3 added the MDCT on top of the analysis filter bank. One of the features of AAC is a simpler method to transform the time domain samples to the frequency domain, which only use the MDCT, not bothering with the band pass filters.

The decoder

Digesting this information about the encoder leads to a startling realization: we can’t actually decode granules, or frames, independently! Due to the overlapping nature of the MDCT we need the inverse-MDCT output of the previous granule to decode the current granule.

This is where chunkBlockType and chunkBlockFlag are used. If chunkBlockFlag is set to the value LongBlocks, the encoder used a single 36-point MDCT for all 32 subbands (from the filter bank), with overlapping from the previous granule. If the value is ShortBlocks instead, three shorter 12-point MDCT:s were used. chunkBlockFlag can also be MixedBlocks. In this case the two lower frequency subbands from the filter bank are treated as LongBlocks, and the rest as ShortBlocks.

The value chunkBlockType is an integer, either 0,1,2 or 3. This decides which window is used. These window functions are pretty straightforward and similar, one is for the long blocks, one is for the three short blocks, and the two others are used exactly before and after a transition between a long and short block.

Before we do the inverse MDCT, we have to take some deficiencies of the encoder’s analysis filter bank into account. The downsampling in the filter bank introduces some aliasing (where signals are indistinguishable from other signals), but in such a way the synthesis filter bank cancels the aliasing. After the MDCT, the encoder will remove some of this aliasing. This, of course, means we have to undo this alias reduction in our decoder, prior the IMDCT. Otherwise the alias cancellation property of the synthesis filter bank will not work.

When we’ve dealt with the aliasing, we can IMDCT and then window, remembering to overlap with the output from the previous granule. For short blocks, the three small individual IMDCT inputs are overlapped directly, and this result is then treated as a long block.

The word “overlap” requires some clarifications in the context of the inverse transform. When we speak of the MDCT, a function from 2N inputs to N outputs, this just means we use half the previous samples as inputs to the function. If we’ve just MDCT:ed 36 input samples from offset 0 in a long sequence, we then MDCT 36 new samples from offset 18.

When we speak of the IMDCT, a function from N inputs to 2N outputs, there’s an addition step needed to reconstruct the original sequence. We do the IMDCT on the first 18 samples from the output sequence above. This gives us 36 samples. Output 18..35 are added, element wise, to output 0..17 of the IMDCT output of the next 18 samples. Here’s an illustration.

With that out of the way, here’s some code:

mp3IMDCT :: BlockFlag -> Int -> [Frequency] -> [Sample] -> ([Sample], [Sample])
mp3IMDCT blockflag blocktype freq overlap =
    let (samples, overlap') = 
            case blockflag of
                 LongBlocks  -> transf (doImdctLong blocktype) freq
                 ShortBlocks -> transf (doImdctShort) freq
                 MixedBlocks -> transf (doImdctLong 0)  (take 36 freq) <++>
                                transf (doImdctShort) (drop 36 freq)
        samples' = zipWith (+) samples overlap
    in (samples', overlap')
        transf imdctfunc input = unzipConcat $ mapBlock 18 toSO input
                -- toSO takes 18 input samples b and computes 36 time samples
                -- by the IMDCT. These are further divided into two equal
                -- parts (S, O) where S are time samples for this frame
                -- and O are values to be overlapped in the next frame.
                toSO b = splitAt 18 (imdctfunc b)
                unzipConcat xs = let (a, b) = unzip xs
                                 in (concat a, concat b)

doImdctLong :: Int -> [Frequency] -> [Sample]
doImdctLong blocktype f = imdct 18 f `windowWith` tableImdctWindow blocktype

doImdctShort :: [Frequency] -> [Sample]
doImdctShort f = overlap3 shorta shortb shortc
    (f1, f2, f3) = splitAt2 6 f
    shorta       = imdct 6 f1 `windowWith` tableImdctWindow 2
    shortb       = imdct 6 f2 `windowWith` tableImdctWindow 2
    shortc       = imdct 6 f3 `windowWith` tableImdctWindow 2
    overlap3 a b c = 
      p1 ++ (zipWith3 add3 (a ++ p2) (p1 ++ b ++ p1) (p2 ++ c)) ++ p1
        add3 x y z = x+y+z
        p1         = [0,0,0, 0,0,0]
        p2         = [0,0,0, 0,0,0, 0,0,0, 0,0,0]

Before we pass the time domain signal to the synthesis filter bank, there’s one final step. Some subbands from the analysis filter bank have inverted frequency spectra, which the encoder corrects. We have to undo this, as with the alias reduction.

Here are the steps required for taking our frequency samples back to time:

  1. [Frequency] Undo the alias reduction, taking the block flag into account.
  2. [Frequency] Perform the IMDCT, taking the block flag into account.
  3. [Time] Invert the frequency spectra for some bands.
  4. [Time] Synthesis filter bank.

A typical MP3 decoder will spend most of its time in the synthesis filter bank – it is by far the most computationally heavy part of the decoder. In our decoder, we will use the (slow) implementation from the specification. Typical real world decoders, such as the one in your favorite media player, use a highly optimized version of the filter bank using a transform in a clever way. We will not delve in this optimization technique further.

Step 4, summary

It’s easy to miss the forest for the trees, but we have to remember this decoding step is conceptually simple; it’s just messy in MP3 because the designers reused parts from layer 1, which makes the boundaries between time domain, frequency domain and granule less clear.

Using the decoder

Using the decoder is a matter of creating a bit stream, initializing it (mp3Seek), unpacking it to an MP3Data (mp3Unpack) and then decoding the MP3Data with mp3Decode. The decoder does not use any advanced Haskell concepts externally, such as state monads, so hopefully the language will not get in the way of the audio.

module Codec.Audio.MP3.Decoder (
) where

mp3Decode :: MP3DecodeState -> MP3Data -> (MP3DecodeState, [Sample], [Sample])

data MP3DecodeState = ...

emptyMP3DecodeState :: MP3DecodeState
emptyMP3DecodeState = ...

The code is tested with a new version of GHC. The decoder requires binary-strict, which can be found at Hackage. See README in the code for build instructions. Please note that the software is currently version 0.0.1 – it’s very, very slow, and has some missing features.

Code: mp3decoder-0.0.1.tar.gz.


MP3 has its peculiarities, especially the hybrid filter bank, but it’s still a nice codec with a firm grounding in psychoacoustic principles. Not standardizing the encoder was a good choice by the MPEG-1 team, and the available encoders show it’s possible to compress audio satisfactory within the constraints set by the decoder.

If you decide to play around with the source code, be sure to set your sound card to a low volume if you use headphones! Removing parts of the decoder may result in noise. Have fun.


CD 11172-3 Part 3 (the specification)

David Salomon, Data Compression: The Complete Reference, 3rd ed.

Davis Pan, A Tutorial on MPEG/Audio Compression

Rassol Raissi, The Theory Behind Mp3

The source code to libmad, LAME and 8Hz-mp3.


Blogger Ram said...

A very good article. Keep writing more of these:)

Wednesday, October 1, 2008 at 11:25:00 PM GMT+2  
Blogger robottaway said...

Bjorn, thanks this article is really top notch. I've just been studying up on Haskell, which I used back in college. I found this:

and have been working through it. This article provides a great real world Haskell project. Keep it coming!

Wednesday, October 1, 2008 at 11:29:00 PM GMT+2  
Blogger Animesh Sharma said...

Kudos to you for putting up such high quality article. I never imagined that I would learn so much about Haskell and MP3 format in just 1 hour!
Please keep writing such articles.

Thursday, October 2, 2008 at 11:21:00 AM GMT+2  
Blogger maasha said...

Write some more stuff on DNA compression!

Friday, October 3, 2008 at 7:21:00 AM GMT+2  
Blogger cjb said...

Thanks! I admire your writing style, this is an excellent article.

Friday, October 3, 2008 at 11:28:00 PM GMT+2  
Blogger Wei Hu said...

According to, the sync word is the higher 12 bits, instead of 11 bits. I made the following changes:

$ diff Unpack.hs Unpack.old.hs
< | bitsSync /= 0xfff = Nothing
< | bitsMpeg /= 1 = Nothing -- We only support MPEG1 (bits=1)
> | bitsSync /= 0x7ff = Nothing
> | bitsMpeg /= 3 = Nothing -- We only support MPEG1 (bits=3)
< bitsSync = bitInterval bits 20 12
< bitsMpeg = bitInterval bits 19 1
> bitsSync = bitInterval bits 21 11
> bitsMpeg = bitInterval bits 19 2

Wednesday, October 8, 2008 at 2:08:00 AM GMT+2  
Blogger Björn Edström said...

Thanks Wei Hu. The sync word is 12 bits for MPEG-1, but was later changed to 11 bits in MPEG-2 to get another bit for the version field. Will add the change to 0.0.2, thanks!

Wednesday, October 8, 2008 at 4:00:00 PM GMT+2  
Blogger Sven Heyll said...

greate article, I really learned something I always wanted to know.

Monday, December 1, 2008 at 9:54:00 AM GMT+1  
Blogger Mamut said...

Would yo mind if I translated your post into Russian for a Russian programmin wiki?

Wednesday, December 24, 2008 at 11:28:00 PM GMT+1  
Blogger vijay sohra said...

Mind Blowing!!! i have been working on this since quite a few days, but it is your article that gav ethe actual insight. even though i never heard of anything like haskel, your article will allow me to make my codec in c. i wanted to port it to atmel microcontroller. good work brother. have you written any books or something. i would like to read your creation.

Wednesday, December 31, 2008 at 12:18:00 AM GMT+1  
Blogger Vinod Kumar Saini said...

Tuesday, January 6, 2009 at 12:23:00 PM GMT+1  
Blogger Vinod Kumar Saini said...

Tuesday, January 6, 2009 at 12:24:00 PM GMT+1  
Blogger akhilesh said...

Best website links related to Online Job sites in India!

In order achieve success in their job search, job seekers must target a wide range of Job sites and use all the available resources. Yes, its time consuming. However, dedicating the time and energy will pay off with more and better job leads, more interviews and more job offers!

Thursday, January 8, 2009 at 12:38:00 PM GMT+1  
Blogger Kyle said...

Excellent overview. I've been working on a decoder for a few months, and every time I step away from the project for a week or so I have to remind myself exactly how everything is working together. This should help jog my memory faster than the ISO doc...

Friday, January 16, 2009 at 2:54:00 PM GMT+1  
Blogger Thompson said...

industrial computers
These computers are best suitable for many automated manufacturing process such as application like stock control and dispatch however their needs are quite a different one. There’sa lot different environment to run the Industrial PC’s. .

Thursday, June 11, 2009 at 1:47:00 PM GMT+2  
Blogger Reducto said...

hello. my name is ahmed hassan and i am making a mp3 decoder on matlab as my final year project...i am having trouble deciding wat to do when the parameter part2_3_length is equal to zero...plz help me

Tuesday, June 23, 2009 at 8:12:00 PM GMT+2  
Blogger ganesh said...

Mp3 download site to download mp3 music legally. Use mp3 music search and download mp3 from over 4 million mp3 downloads mp3 music

Thursday, November 12, 2009 at 3:01:00 PM GMT+1  
Blogger TUTU said...

表参道 エステ
福生市 不動産
三軒茶屋 不動産
婚活 悩み
フランチャイズ カフェ
大井町線 一戸建て
飲食 求人
ギフト ベビー
ダイビング ツアー
子宮腺筋症 漢方
クロエ バッグ
店舗デザイン 東京
東京 皮膚科
簿記 通信
志木 不動産
外資 英語

Wednesday, November 25, 2009 at 3:23:00 PM GMT+1  
Blogger TUTU said...

結婚 悩み
お見合いパーティー 大阪
新座市 一戸建て
川越市 一戸建て
柏市 一戸建て
春日部市 一戸建て
埼玉県 不動産
海水魚 通販
東横線 土地
エアコン 工事
エルメス 財布
株 投資
オフィス レイアウト変更
home loans
自己破産 無料相談
ダビング サービス
ロレックス 修理
老人ホーム 神奈川
恵比寿 物件
中古 厨房機器
バイク便 東京
ECサイト 構築 システム
ピアノ レンタル
債務整理 相談
自己破産 名古屋
埼玉 一戸建て

Wednesday, November 25, 2009 at 3:23:00 PM GMT+1  
Blogger Slider2009 said...

World music collection in MP3.
Your music choice can be satisfied with our music archive download mp3
It's 100% legal, no DRM, no limited copy. A lot for free.
Radio rips & live without charge.

Tuesday, December 1, 2009 at 12:34:00 PM GMT+1  
Blogger Sachin said...

This comment has been removed by the author.

Friday, January 15, 2010 at 5:06:00 AM GMT+1  
Blogger Sachin said...

hello! can you give me pointers on what all modifications will be required to decode an mp2 file?

Friday, January 15, 2010 at 5:07:00 AM GMT+1  
Blogger jimmychooshoes said...

mcqueen shoes
alexander mcqueen heels
Alexander McQueen Store
Jimmy Choo sale
Replica jimmy choo shoes
manolo blahnik online store
manolo shoes
manolo blahnik sale
replica christian louboutin shoes
discount christian louboutin shoes
alexander mcqueen shoes
jimmy choo outlet
jimmy choos
jimmy shoes
Manolo Blahnik Shoes
christian shoes

alexander mcqueen shoes
Alexander McQueen Band leather sandals

Sunday, August 8, 2010 at 1:13:00 PM GMT+2  
Blogger Dimitri B. said...

A very good article! Easy to understand and good structured! Well done!

Friday, August 13, 2010 at 3:16:00 PM GMT+2  
Blogger برامج said...

wow this is too easy i never thought it is

Saturday, October 9, 2010 at 10:00:00 PM GMT+2  
Blogger raj said...

I strongly imagine that the know-how presented is strongly related nearly everybody . Thanks a ton .
Long Beach Locksmiths
locksmith bridgeport ct
Berkeley locksmith
Locksmith Santa Clara CA
Santa Clara locksmith
Locksmith Santa Clara CA
Locksmith Santa Clara CA
Santa Clara locksmith
Locksmith Arlington Hts IL
Locksmith Arlington Hts IL
Locksmith Arlington Hts IL
Locksmith Arlington Hts IL
Locksmith Arlington Hts
Locksmith Arlington Hts
Locksmith Arlington Hts
Arlington Hts Locksmith
Locksmith Arlington Hts
Locksmith Arlington Hts
Locksmith Arlington Hts IL
Locksmith Arlington Hts IL
Locksmith Arlington Hts IL
Locksmith Arlington Hts
miami locksmiths
locksmiths fort worth
locksmith aventura
miami beach locksmith
miami beach locksmith
locksmith aventura
miami beach locksmith
miami beach locksmith

Tuesday, March 15, 2011 at 11:21:00 AM GMT+1  
Blogger vibrams said...

All the cheap christian louboutin heels for retailing inside our store can be to offer solutions of first-class quality. The christian louboutin evening complete great deal could possibly be the fine and fashionable one.They take place in fascinating design and layout and fashionable appearnce.The colourway also is quite popular. These christian louboutin pumps are luxury and noble. The christian louboutin peep toe show formal, a complete great deal extra show its gorgeous gloss and honour. hold into some mysterious alluring taste! This pairs of christian louboutin 2011 sandals attributes a quite considerable component for women's fabulous whole system figure, show their fabulous figure and fashionable gesture. Louboutin heels is a good choice for you, welcome to our Christian louboutin store!

Tuesday, May 31, 2011 at 3:08:00 PM GMT+2  
Blogger abercrombiefitch said...

Be fast to browse the newest styles and lots of affordable outfits and Nike oxygen Max and women's merchandise is not an daily affair, for that reason that in the stress of modern day time girls ordinarily do not possess a complete great offer time and vitality to go buying by means of countless many style malls, and look at special fees will make you exhausted, so which you can acquire a satisfactory goods, call up for to devote lots of time, the show up of on collection buying significantly minimizing the inconvenience of this, now you not just can every one of the sudden go to to lots of goods Nike Air Max Shoes .

Friday, June 17, 2011 at 3:30:00 AM GMT+2  
Blogger nikeairmaxshoe said...

Most women would love to own an authentic cheap Christian Louboutin Outletthat fits their budget.Christian Louboutin Discount We have heard stories that it is possible to find discounted designer shoes, but it is easy to get frustrated when the cheapest shoes you are able to find are priced well into the hundreds of dollars.Let's cut right to the chase. However desirable all but the wealthiest women may find designer label shoes, Louboutin Outletmost of us are going to have at best one or two cheap christian louboutin clearance shoes if we insist on buying new at retail.Christian Louboutin 2011 Christian Louboutin Ankle Shoes if we want to have an assortment of such treasures, we're going to have to make our purchases of lower-priced, Christian Louboutin Heelsdare I say cheap shoes, while not sacrificing original designer heritage for them.Christian Louboutin Peep ToeOf course, Christian Louboutin Sandalssome education is in order. Some people suggest going to christian louboutin outlet stores and examining the goods found there.Christian Louboutin Tall ShoesSuch a plan can be an advantage, Ghd Australia in the outlet store.
Five Fingers Shoes
Happy to see this article as it is just what I have looking for and I am looking forward to another great article from you. You may be interested in CHI us
Your space is really pretty, have no interest in to my chi for sale space to share it? thank you Oh.Buy Nike Shoes
2011 Cheap Nike Air Max Online Store,Nike Air Max Shoes,Nike Outlets Online.

Friday, June 17, 2011 at 11:29:00 AM GMT+2  
Blogger Hines said...

Thanks for sharing this useful article! It helped me a lot to build an mp3 decoder.

YouTube converter

Tuesday, July 12, 2011 at 11:07:00 AM GMT+2  
Blogger Christian Louboutin sale said...

Monsieur Louboutin once said, "sexy is too vast to be defined, but more than anything it's an attitude much like elegance." Christian Louboutin sale is the perfect juxtaposition between sexiness and elegance. Whether you dress her up or dress her down, she will add a bit of attitude to any ensemble.

Wednesday, July 13, 2011 at 5:29:00 AM GMT+2  
Blogger Mari said...

i truthfully enjoy your own writing kind, very remarkable,
don’t give up as well as keep writing due to the fact that it simply just worth to follow it.
looking forward to see a whole lot more of your current well written articles, enjoy your day

Thursday, July 14, 2011 at 1:17:00 PM GMT+2  
Blogger Mari said...

What a great web log. I spend hours on the net reading blogs, about tons of various subjects. I have to first of all give praise to whoever created your theme and second of all to you for writing what i can only describe as an fabulous article. I honestly believe there is a skill to writing articles that only very few posses and honestly you got it. The combining of demonstrative and upper-class content is by all odds super rare with the astronomic amount of blogs on the cyberspace.
I have bookmarked, Dugg, and I joined the RSS subscription. Thanks! ….
Dominican Republic Real Estate

Thursday, July 14, 2011 at 1:18:00 PM GMT+2  
Blogger Christian Louboutin sale said...

cheap louboutin shoes are a necessary weapon for a sexy woman, every year, stylist can use heels give women surprise, series of high-heeled shoes entice every woman's heart, just like this Christian louboutin sale shoes. It can bring strong charm for you!

Saturday, July 16, 2011 at 4:50:00 AM GMT+2  
Blogger Christian Louboutin sale said...

Welcome to our Cheap louboutin shoes online shop.Pair this<a href="</a>Christian Louboutin Sandals </a>with your favorite black dress, rouge lip, and "Eden" clutch for the ultimate Louboutin girl look.

Monday, July 18, 2011 at 5:23:00 AM GMT+2  
Blogger Christian Louboutin sale said...

Tuesday, July 19, 2011 at 5:41:00 AM GMT+2  
Blogger Christian Louboutin sale said...

1964-Christian Louboutin sale shoes is born and brought up in Paris's 12th. arrondissement.
1975-On the wall from the African and Oceanic art work Museum,Louboutin is struck with a unusual drawing:a woman's shoe getting a sharp heel, slashed-out getting a red line.
1980-1986-Louboutin's first occupation is in the Folies Bergeres, the well-known French audio tracks Hall He follows this apprenticeship by freelancing for Chanel,Yves Saint Laurent Maud Frizon as well as other prestigious style houses.
1989-Louboutin turns to garden design.
1992-Creation from the Christian Louboutin shoes brand, and opening from the very first boutique in Paris.
1994-Opening the first New York city boutique.
1995-For Jean-Paul Gaultier,Chloe,Azzaro,Diane Von Furstenberg,Victor &Rolf, Givebchy and Lanvin,Louboutin starts to contribute for couture and ready-to-wear seasons.
2002-At Yves Saint Laurent's farewell haute-couture show,Louboutin creats a shoe for that finale.Referred to as , it represents the only time that Saint Laurent associates his name with one more designer.
2007-Cheap louboutin shoes collaborates with director David Lynch for the exhibition , which exhibits alluring one-off objects: fetishist shoes,photographed by Lynch.
2008-New York's style Institue of engineering pays a tribute to Louboutin, mounting an essential retrospective of his work. afterwards that year, Louboutin may be the Star Honoree in the style set worldwide as well as receiving a 2nd FFANY Award.

Tuesday, July 19, 2011 at 5:50:00 AM GMT+2  
Blogger Christian Louboutin sale said...

Welcome to our Cheap louboutin shoes online shop.Double your sex appeal with the Christian Louboutin Peep-Toe. Christian Louboutin Pumps was made for the lady who is feminine and confident. We also shop for Christian Louboutin Tall Shoes.

Wednesday, July 20, 2011 at 4:41:00 AM GMT+2  
Blogger Hines said...

Thanks for the informative article!
I also like to watch free TV online:) Do you?

Wednesday, July 27, 2011 at 11:59:00 AM GMT+2  
Blogger Christian Louboutin sale said...

Create a real warming trend. Contoured silhouette make cheap moncler coats winter essential. For generations, world-class competitive skiers and mountaineers have turned to moncler uk for premium, performance-oriented apparel.Stay warm—and look cool—in this cozy quilted puffer,it's everything you could ever want out of cold-weather cheap moncler coats.

Wednesday, August 3, 2011 at 8:45:00 AM GMT+2  
Blogger Christian Louboutin sale said...

Is it possible you don't have the ideal hair brush for your style? A Babyliss Hair Straightener give your cut that hairstyle you've been longing for.

Wednesday, August 3, 2011 at 8:45:00 AM GMT+2  
Blogger hibeyond said...

black boots

Chocolate boots

sand boots

Chestnut boots

gray boots

pink boots

grey boots

pink boots

Wednesday, August 10, 2011 at 5:46:00 AM GMT+2  
Blogger Christian Louboutin sale said...

colorful quilted 'moncler uk ' short puffer down cheap moncler coats. Streamline your cold weather wardrobe with contemporary designs. Premium cheap moncler coats down fill provides lightweight warmth, enabling a figure-flattering silhouette. Is it possible you don't have the ideal hair brush for your style? A Babyliss Hair Straightener give your cut that hairstyle you've been longing for.
Here are the discount Christian louboutin shoes.

Monday, August 15, 2011 at 8:33:00 AM GMT+2  
Blogger Christian Louboutin sale said...

everybody talks about <moncler uk , cheap moncler coatsthat are sold out everywhere. Wear cheap moncler jackets with any basic outfit to add a little bit of fun and flirtiness to your outfit.
A Babyliss Hair Straightener give your cut that hairstyle you've been longing for.
Here are the discount Christian louboutin shoes.

Friday, August 19, 2011 at 5:26:00 AM GMT+2  
Blogger Christian Louboutin sale said...

The low-pitched luxurious style of moncler uk on hot sale!The clean design lines and the signature red sole become a classic.
A Babyliss Hair Straightener give your cut that hairstyle you've been longing for.

Monday, August 22, 2011 at 5:54:00 AM GMT+2  
Blogger KING MAZHAR said...

Nice achivement keep it up Song pk free download

Monday, August 22, 2011 at 7:48:00 PM GMT+2  
Blogger KING MAZHAR said...

Nice achivement keep it up Song pk free download

Monday, August 22, 2011 at 7:49:00 PM GMT+2  
Blogger KING MAZHAR said...

Nice achivement keep it up Song pk free download

Monday, August 22, 2011 at 7:49:00 PM GMT+2  
Blogger Christian Louboutin sale said...

Here are the discount Christian louboutin shoes.
everybody talks about <moncler uk , cheap moncler coatsthat are sold out everywhere. Wear cheap moncler jackets with any basic outfit to add a little bit of fun and flirtiness to your outfit.
A Babyliss Hair Straightener give your cut that hairstyle you've been longing for.

Friday, August 26, 2011 at 5:02:00 AM GMT+2  
Blogger hbalxb said...

Hi, Would you like to have a pair of good and cheap ugg boots? We have varies of uggs on sale. They are:
UGG Bailey Button Triplet Boots

UGG Bailey Button Boots

UGG Classic Tall Boots

UGG Classic Short Boots

UGG Classic Cardy Boots

Ugg Classic Argyle Knit Boots

UGG Classic Mini Boots

UGG Classic Paisley Boots

UGG Metallic Short Boots

UGG Metallic Tall Boots

Ugg Stripe Cable Knit Boots

UGG Sundance II Boots

UGG Tall Baroque Boots

UGG Ultra Short Boots

UGG Ultra Tall Boots

UGG Nightfall Boots

Ugg Boots For Sale

Sand Ugg Boots

Tuesday, September 13, 2011 at 10:24:00 AM GMT+2  
Blogger hbalxb said...

Hi, Would you like to have a pair of good and cheap ugg boots? We have varies of uggs on sale. They are:
[url=]ugg boots[/url]
[url=]cheap ugg boots[/url]
[url=]uk ugg boots sale[/url]
[url=]ugg boots sale[/url]
[url=]UGG Bailey Button Triplet Boots[/url]
[url=]UGG Bailey Button Boots[/url]
[url=]UGG Classic Tall Boots[/url]
[url=]UGG Classic Short Boots[/url]
[url=]UGG Classic Cardy Boots[/url]
[url=]Ugg Classic Argyle Knit Boots[/url]
[url=]UGG Classic Mini Boots[/url]
[url=]UGG Classic Paisley Boots[/url]
[url=]UGG Metallic Short Boots[/url]
[url=]UGG Metallic Tall Boots[/url]
[url=]Ugg Stripe Cable Knit Boots[/url]
[url=]UGG Sundance II Boots[/url]
[url=]UGG Tall Baroque Boots[/url]
[url=]UGG Ultra Short Boots[/url]
[url=]UGG Ultra Tall Boots[/url]
[url=]UGG Nightfall Boots[/url]
[url=][b]Ugg Boots For Sale[/b][/url]
[url=][b]Sand Ugg Boots[/b][/url]

Saturday, September 17, 2011 at 5:49:00 AM GMT+2  
Blogger Evolve said...

i truthfully enjoy your own writing kind, very remarkable,
don’t give up as well as keep writing due to the fact that it simply just worth to follow it. looking forward to see a whole lot more of your current well written articles, enjoy your day
London Chartered Accountants

Friday, September 23, 2011 at 8:41:00 AM GMT+2  
Blogger Bernice said...

This comment has been removed by the author.

Monday, October 24, 2011 at 12:50:00 PM GMT+2  
Blogger Bernice said...

This comment has been removed by the author.

Monday, October 24, 2011 at 12:50:00 PM GMT+2  
Blogger Bernice said...

Thanks for information. It's very usefull. See mp4 player software here
MP4 player software

Monday, October 24, 2011 at 12:54:00 PM GMT+2  
Blogger Justice88 said...

Awesome article filled with sense.

WMV player free download

Friday, October 28, 2011 at 4:50:00 PM GMT+2  
Blogger blog seven gokil said...

this post is very helpful for us.

and do not forget to also visit our blog:

Berita Yang Melintas, Informasi Terkini, Berita Online, Ramalan, Info Terupdate Terkini, Ramalan Terbaru, Info Terbaru Hari Ini, Sekilas Warta, Warta Terbaru, Pos Berita, Kabar Terbaru, Seputar Warta, Berita Terbaru, Tyo89, Complex90, Game Online IndonesiaShared Info,chen's blog,Info online 2012,Berita Terbaru,Info Handphone Terbaru,The Base Information, Arselo, Harga Spesifikasi HP

Wednesday, November 2, 2011 at 10:48:00 AM GMT+1  
Blogger Admin said...

Although there were rumors that the site will soon be blocked 4forshared Indonesia, but in fact, this site can still be visited today, and you can still find and download the latest MP3 for free.

The steps to get the latest MP3 4forshared is so easy, it's just to visit, once you get the page, and there will also find the latest MP3.

Just type the name of the song or singer's name, where you want to access MP3 downloads, and immediately after the songs will soon appear in search results.

When the search has produced the song appeared, then you live so just download mp3 for free. However, we do this wisely, so that what we do, ie try to download the song does not violate the rights reserved to others, and each of them to return, respectively.

Thus, writing about this new MP3 4shared arrived here first, again, I hope we can use the site wisely 4forshared dry without harming others, it may be useful.

Thursday, November 3, 2011 at 5:03:00 AM GMT+1  
Blogger aigreen said...

To experience Australia Luxe Collective Crystal Angel Short Black Boots the Hollywood phenomena and be treated like Hollywood's favorite flavor of the month, check out the Australia Luxe Collective Angel Short Distressed Brown Boots Tropicana Bar inside the Roosevelt Hotel. This legendary-status A-list getaway for drinks or a night out has been serving the community stalwartly since 1927.

It is a fortress of lush, tropical luxury located in the center of Hollywood near Australia Luxe Bedouin Boots Grauman's Chinese Theater and the Hollywood Walk of Fame. Maybe it is just the poolside bar and the mix of old and new decadence Luxe Bedouin Classic Brown Tall Boots bonding seamlessly in this community of cabanas and a poolside-bar.

Monday, November 14, 2011 at 5:00:00 AM GMT+1  
Blogger mbah topo said...

It nice an article, I like it. thank you for your information.

Antivirus Terbaik

Monday, November 14, 2011 at 5:15:00 PM GMT+1  
Blogger escort ankara said...

Nice information,Ankara escort
many thanks to the author.Ankara escort
It is incomprehensible to me nowAnkara escort
, but in general,Escort ankara bayan
the usefulness and significance is overwhelming.Ankara escort
Thanks again and good luck!
Ankara escort
became the first designer in Wimbledon's 133-year history to create official uniforms for the tournamentescort bayan ankara
As part of this year's event, which starts next week.
will introduces the first ...Escort ankara
determinationEscort ankara
to maintain and enhance the values for which our two brands are famous throughout the world.Escort ankara
The rugby ralph lauren brand brings to Wimbledon the look of timeless elegance,Escort ankara
drawing on our rich history and traditionsEscort ankara
expert and i like your blog and the information you have
mentioned in this post about the Google tools is really great!
escort bayan
escort bayan ankara
escort bayan ankara
escort bayan ankara kızılay
Escort ankara bayan
escort bayan ankara çankaya
Ankara escort bayan
Ankara escort bayan
Ankara Escort

Thanks for sharing. Very impressive

Tuesday, December 6, 2011 at 3:08:00 PM GMT+1  
Blogger Evan Gardner said...

This is a very informative and useful article about mp3 - we all come across this format every day, but most of us have never really wondered what is is all about. I think an article about how to handle flac to mp3 converter may be also helpful to the music fans. Look here:

Tuesday, January 10, 2012 at 12:56:00 PM GMT+1  
Blogger London Crumpet said...

London Crumpet has a message board where London escorts and agencies can post their messages about their services or announce people about any update of their profile. Visitors can also rate the escorts on Hot or Not gallery and give some credentials to the escorts they like.

Thursday, April 19, 2012 at 12:46:00 PM GMT+2  
Blogger aven peter said...

Thanks for information. I realize it's been a few years, but this just came in handy for me.
See mp4 converter software here; mov to vob mac

Thursday, August 2, 2012 at 8:55:00 AM GMT+2  
Blogger aven peter said...

Excellent overview. I've been working on a decoder for a few months, and every time I step away from the project for a week or so I have to remind myself exactly how everything is working together. This should help jog my memory faster than the ISO doc...convert mov to flv

Thursday, August 2, 2012 at 10:09:00 AM GMT+2  
Blogger aven peter said...

I have an iPhone 4 with iOS 4.2.1 and I am using greenpois0n to jailbreak it. I put it in DFU mode then the software writes and the greenpois0n logo appears, but when it is all done my iPhone goes into recovery mode. I tried it about 5 times, after restoring every time. I am using a Mac. Does anyone know why this is happening or how I can jailbreak my iPhone?
how to recover iphone 4 data

Tuesday, August 21, 2012 at 11:11:00 AM GMT+2  
Blogger Bayan Ankara Escort said...

Ankara Escort, Escort Ankara, Escort Ankara Bayan
Escort Ankara, Escort Ankara Bayan, Ankara Escort Bayan
Bayan Ankara Escort, Ankara Bayan Escort, Ankara Escort Kızlar
Escort Kızlar Ankara, Escort Bayan Ankara, Escort Bayanlar Ankara
Escort Bayanlar Ankara, Ankara Bayan Escortlar, Ankara Eskort Bayan
Escort Kızlar Ankara, Ankara Escort Kadınlar, Ankara Eskort Bayanlar
Ankarada Tele Kızlar, Ankara Escort Kızlar, Ankara Eskort Bayan
Bursa Escort, Bayan Escort Bursa, Bursa Eskort Bayan
Kayseri Escort, Bayan Escort Kayseri, Kayseri Eskort Bayan ,
Escort Bayan Ankara ,
Escort Bayan,
Escort Ankara ,
Escort Ankara Bayan ,
Escort Bayan Ankara ,
Ankara Escort ,
Ankara Escort Bayan ,
Escort Bayan Ankara ,
Escort Bayan ,
Escort Ankara Bayan ,
Ankara Escort ,
Ankara Escort Bayan ,
Escort Bayan Ankara ,
Ankara Escort Bayan ,
Escort Ankara,
Bayan Ankara Escort ,
Escort Ankara ,
Escort Bursa,
Escort Ankara Bayan,
Ankara Escort Bayan ,
Ankara Günlük Kiralık Ev ,
Escort Ankara Bayan ,
Thanks for sharing. Very impressive

Tuesday, August 28, 2012 at 10:50:00 AM GMT+2  
Blogger Alisa Fish said...

such a nice post for me to learn things about MP3.
Thank you for your share, and I do like to share you how to convert MP4 to MP4 easily.

Thursday, November 1, 2012 at 3:13:00 AM GMT+1  
Blogger Unknown said...

Site's character and a great color match .. Göğüs estetiğiI will recommend your site to the other platforms.

Saturday, February 2, 2013 at 9:56:00 AM GMT+1  
Blogger SummitTechnology said...

You can learn ti build mp3 decoder with help of the article here. Thanks for sharing. Useful post
CD printing

Tuesday, February 5, 2013 at 6:53:00 AM GMT+1  
Blogger Promo Disc said...

Loved to read your blog. I would like to suggest you that traffic show most people read blogs on Mondays. So it should encourage blogger to write new write ups over the weekend primarily
DVD packaging

Saturday, February 23, 2013 at 10:01:00 AM GMT+1  
Blogger Rahul said...

Huffman decoding table???

Thursday, May 30, 2013 at 6:30:00 AM GMT+2  
Blogger metin aksoy said...

A court in Moscow has found escort bayan late Russian lawyer Sergei Magnitsky guilty of tax fraud.Magnitsky was arrested in 2008 after accusing officials of tax fraud but was later himself accused of those crimes.His death in custody a year escortlater led to a major diplomatic dispute between Russia and the United States.William Browder, CEO of Hermitage Capital Management, which Magnitsky represented, was found guilty in absentia and sentenced to nine years.

Browder, a US-born British citizen, is in London, where the firm is based.He has denied the charges and says the trial was politically motivated. His defence team have escort istanbulsaid they will appeal against the verdict.No sentence will be passed for Magnitsky, whose relatives regard the case as illegal.A lawyer for the family told Russia's escort Rapsi news agency: "I did not doubt that the decision would look like this."

Instead of Putin bringing justice escort istanbul he exonerated all the officials involved and prosecuted the whistle blowers”

Employed as an auditor for Hermitage, Magnitsky uncovered what he described as a web of corruption bayan escort involving Russian tax officials, including the alleged theft of more than $200m (£125m).After reporting the allegations to the authorities, he was himself detained on suspicion of helping Hermitage evade $17.4m in taxes.

He had pancreatitis and died in custody escort in 2009, but an investigation by Russia's presidential council on human rights concluded that he had been severely beaten and denied medical treatment.

Last December, a Russian court escort bayan acquitted a prison doctor accused of negligence over Mr Magnitsky's death. And in March this year the investigation into his death was dropped altogether due to "lack of evidence of a crime".

Browder has described the charges filed escort against him as an "absurdity" and revenge for his campaign to put pressure on Russia over the Magnitsky case.
Hermitage Fund manager William escort Browder William Browder has spearheaded efforts in the US to put pressure on Russia over the Magnitsky escort beylikduzu case

Speaking to the BBC on Wednesday, he said the trial was "proof" that President Vladimir Putin "will use escort the courts in order to cover up his economic crimes".

"This entire process has been done escort sisli because Sergei Magnitsky discovered a vast $230m fraud by the Russian state, and blew the whistle on the officials who orchestrated the crime, and for that he was tortured escort atasehir and killed in police custody and then prosecuted afterwards," he said.

"Instead of Putin bringing justice, escort maltepe he exonerated all the officials involved and prosecuted the whistle blowers.

Thursday, July 11, 2013 at 3:38:00 PM GMT+2  
Blogger Ankara Kızlar said...

ankara escort,
escort ankara,

ankara escort,
escort ankara,

mersin escort,
izmir escort,
bursa escort,
bodrum escort,
seks hikayeler,

Thursday, February 13, 2014 at 3:12:00 PM GMT+1  
Blogger Avcı Mimarlık said...

Eskişehir Escort Bayan |
Ankara Escort
Ankara Escort
Ankara Escort
Ankara Escort

Ankara Escort

Saturday, March 29, 2014 at 1:50:00 AM GMT+1  
Blogger Avcı Mimarlık said...

Gaziantep Escort
Adana Escort
Mersin Escort
İzmit Escort
kocaeli Escort
Bodrum Escort

Saturday, March 29, 2014 at 6:02:00 PM GMT+1  
Blogger Avcı Mimarlık said...

Kocaeli Escort
izmit Escort
Adana Escort
Mersin Escort
Gaziantep Escort
Bodrum Escort
Denizli Escort
Kuşadası Escort
Manisa Escort

Sunday, April 13, 2014 at 1:49:00 AM GMT+2  

Post a Comment

Subscribe to Post Comments [Atom]

<< Home