Question

I am learning visual basic .net and I am attempting to translate some java source code to a vb.net project. The project reads mp3 details and then splits the file accurately according to the frameheader details etc.

My question relates to reading the frame header of mp3 files. I understand that the frame details are contained in the first 4 (32-bits) bytes of a frame and certain bits represent certain values as detailed here: http://www.mp3-tech.org/programmer/frame_header.html

Using FileStream I have been able to read this data and display it in binary within a text box.

I am looking for help on reading the bits and assigning them to variables within my class. I am not sure what would be the correct procedure to do this as some values as 1, 2 or 4 bits in length e.g. bits 19-20 = MpegType, bits 12-15 = BitrateIndex, bit 9 = Padding etc.

I have looked at similar projects available on codeproject.com but I do not understand how they have achieved the above.

Any help is much appreciated.

EDIT:

Here is the main sub so far, I have not included the code declaring variables and properties etc.

Public Sub decode()
    Dim fs As FileStream
    Dim bytes(3) As Byte
    fs = New FileStream(mFilename, FileMode.Open, FileAccess.Read)

    If fs.CanRead Then
        fs.Read(bytes, 0, bytes.Length)
        For i As Integer = 0 To bytes.Length - 1
            Form1.RichTextBox.Text += Convert.ToString(bytes(i), 2).PadLeft(8, "0"c) & vbCrLf
        Next
        fs.Close()
        fs.Dispose()
    Else
        MsgBox("File CANNOT be read!!!")
    End If
End Sub

When this is run the output in the rich text box is as follows:

11111111
11111010
10110011
01001100

I want to read through these bits and assign the appropriate values to the variables e.g.

Read the first 12 bits for sync value. Read bit 13 for mpegID value. Read bit 14 and 15 for layerID value etc.

Hope that is clearer.

The java code is as follows:

public FrameHeader() {
    this.header32 = 0;
    valid = false;
}

public FrameHeader(int header32) {
    this.header32 = header32;
    decode();
}

public void setHeader32(int header32) {
    this.header32 = header32;
    decode();
}

private void decode() {
    mpegID = (header32 >> 19) & 3;
    layerID = (header32 >> 17) & 3;
    crc16used = (header32 & 0x00010000) == 0;
    bitrateIndex = (header32 >> 12) & 0xF;
    samplingrateIndex = (header32 >> 10) & 3;
    padding = (header32 & 0x00000200) != 0;
    privateBitSet = (header32 & 0x00000100) != 0;
    mode = (header32 >> 6) & 3;
    modeExtension = (header32 >> 4) & 3;
    copyrighted = (header32 & 0x00000008) != 0;
    original = (header32 & 0x00000004) == 0; // bit set -> copy
    emphasis = header32 & 3;
    valid = (mpegID != ILLEGAL_MPEG_ID) && (layerID != ILLEGAL_LAYER_ID) && (bitrateIndex != 0)
            && (bitrateIndex != 15) && (samplingrateIndex != ILLEGAL_SR);
    if (valid) {
        samplingrateHz = SAMPLING_RATES[samplingrateIndex];
        if (mpegID == MPEG2_ID)
            samplingrateHz >>= 1; // 16,22,48 kHz
        if (mpegID == MPEG25_ID)
            samplingrateHz >>= 2; // 8,11,24 kHz
        channels = (mode == MODE_MONO) ? 1 : 2;
        bitrateKBPS = BITRATE_MAP[mpegID][layerID][bitrateIndex];
        if (layerID == LAYER1_ID) {
            // layer 1: always 384 samples/frame and 4byte-slots
            samplesPerFrame = 384;
            bytesPerSlot = 4;
        }
        else {
            // layer 2: always 1152 samples/frame
            // layer 3: MPEG1: 1152 samples/frame, MPEG2/2.5: 576
            // samples/frame
            samplesPerFrame = ((mpegID == MPEG1_ID) || (layerID == LAYER2_ID)) ? 1152 : 576;
            bytesPerSlot = 1;
        }
        frameSize = ((bitrateKBPS * 125) * samplesPerFrame) / samplingrateHz;
        if (bytesPerSlot > 1)
            frameSize -= frameSize % bytesPerSlot;
        if (padding)
            frameSize += bytesPerSlot;
    }
}
Was it helpful?

Solution

Here is a detailed explanation of frames and a formula on how data is held in the header, the first 4 bytes of a frame. I am not sure what you are trying to accomplish but, just in case, here you go. There is no point in reinventing the wheel.

.Net has class called BitArray that you would use to store your bits.

OTHER TIPS

I have come across a similar project that uses a function to converts bits to string. I've combined this code with another example I found that changed a binary string to integer. Interested to hear of alternative methods?

Public Function BinaryToInteger(ByVal objBitArray As BitArray, ByVal intStart As Integer, ByVal intEnd As Integer) As Integer

    Dim BinaryString As String
    Dim BinaryNum As Integer
    Dim BitCount As Short

    BinaryString = ""

    For i As Integer = intStart To intEnd
        BinaryString &= IIf(objBitArray.Item(i), "1", "0")
    Next

    For BitCount = 1 To Len(BinaryString)
        BinaryNum = BinaryNum + (CDbl(Mid(BinaryString, Len(BinaryString) - BitCount + 1, 1)) * (2 ^ (BitCount - 1)))
    Next BitCount

    BinaryToInteger = BinaryNum

End Function
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top