MP3 信息讀取

MP3 信息讀取html

運行環境:Window7 64bit,.NetFramework4.61,C# 7.0; 編者:烏龍哈里 2017-03-13算法


參考:express

章節:windows

  • Mp3 文件結構概述
  • ID3V1 標記
  • ID3V2 標記
  • Mp3 數據頭

正文:數據結構

1、Mp3文件概述ide

最近買了個車載mp3播放器,須要下載mp3文件。下載了一堆後發現,不少網上的mp3音質不怎麼好,如何來分辨呢。只好研究mp3的文件格式。編碼

從 wiki 上獲知,mp3的文件基本有3部分組成:spa

ID3v2x 標記
MP3 音樂數據
ID3v1 標記

2、ID3v1 標記.net

Id3v1標記位於 mp3 文件末尾的128 byte,結構以下:3d

起始 長度 內容
0 3 標記 Tag
3 30 歌曲名 SongTitle
33 30 表演者 Artist
63 30 專輯 Album
93 4 年份 Year
97 30 備註 Comment
127 1 歌曲類型 Genre

一、標記:
標記是以「TAG」3個大寫字母爲標記。

二、內容:
歌名、表演者、專輯、年份、備註都是以ASCII編碼的字符

三、類型:
類型是1位數字,具體見 8.1. Appendix A - Genre List from ID3v1

3、ID3v2 標記

Id3v2 標記是放在mp3文件頭,具體長度要經過計算才知道。結構分爲兩部分: Id3v2 Tag Header,Id3v2 Frame

一、Id3v2Tag Header:
這個頭部放在mp3文件最前面,長 10byte,具體結構:

起始 長度 內容
0 3 標誌 Tag
3 2 版本 version
5 1 Flag
6 4 Frame長度

標誌是以「ID3」3個字符爲標記;
版本爲2個 byte的數字,前面1byte 通常爲 03,表示id3v2.3版本,後面1byte的爲小版本,通常爲0;
Flag具體看ID3 tag version 2.3.0 ,通常爲0;
Frame長度是指緊接着 10byte 長的頭部數據後的id3v2tag Frame的長度,是4個byte的數字,每byte的二進制位中前面都爲0,0xxxxxxxx,具體長度的算法用位計算爲:

byte[] data=new byte[10];
//....(從文件中讀取前10byte數據放入 data)
int FrameLength=data[6] << 21 | data[7] << 14 | data[8] << 7 | data[9]

二、Tag Frame幀數據。
Tag Frame 是一個以10byte爲頭,後面不定長的數據幀,結構以下:

部分 相對起始 長度 內容
0 4 標記 Frame ID
5 4 內容長度
8 2 Flages
內容 10 不定長 內容

FrameID 爲4個字符,具體參考ID3 tag version 2.3.0
內容長度爲 4 byte的數據,和上面的不一樣,它的二進制是全8位的,但和 C# 存儲int32不一樣,它前面的byte表示高位,具體計算以下:

byte[] data=new byte[10];
//....(讀取10byte Frame頭部數據放入 data)
int ContentLength=data[6] << 24 | data[7] << 16 | data[8] << 8 | data[9]

(1)FrameId 以「T」開頭的,除了「TXXX」,都是字符串信息,具體結構爲:

起始 長度 內容
0 1 Text encoding
1 Frame頭計算出來的長度 內容

內容以 FF FE 開頭的爲 C# 裏面的 Encoding.Unicode ,以 FE FF 開頭的爲 C# 裏面的 Encoding.BigEndianUnicode;除上外是以 Ascii 編碼的。

(2)FrameId爲「APIC」的是放 jpeg 或 png 格式的圖像數據,具體見4.15. Attached picture

4、mp3音樂數據頭

讀完 id3v2tag 的數據後,緊接着下來就是具體的音樂數據。可是並不必定緊挨着 FrameLength+10,不知道是這些mp3錄製的時候的軟件問題仍是其餘我還沒發現的問題,用ultraEdit看,音樂數據和 id3tag 中間還有一部分全都是0的數據,因此讀完 id3v2tag 後還要一個字節一個字節的尋找 FF開頭的數據。我只是須要知道mp3的音樂信息,因此只要在id3v2tag 後找到 FF 開頭的4個字節的數據就成了。這4個字節所有都是用位來表示信息,具體見 MPEG Audio Layer I/II/III frame header

寫了一個程序讀寫,還沒有徹底完成,效果以下圖:

附練手全程序:

<Window x:Class="Mp3信息.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Mp3信息"
        mc:Ignorable="d"
        Title="Mp3信息1.0  [烏龍哈里2017-03-13]" Height="650" Width="500">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="32"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid Grid.Row="0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="1*"/>
                <ColumnDefinition Width="6*"/>
            </Grid.ColumnDefinitions>
            <Button Name="btnFile" Content="Mp3" Margin="3" Grid.Column="0" Click="btnFile_Click"/>
            <TextBox Name="txtFile" Grid.Column="1" Margin="3"/>
        </Grid>
        
        <TabControl Grid.Row="1">
            
            <TabItem Header="單曲">
                <Grid >
                    <Grid.RowDefinitions>
                        <RowDefinition Height="*"/>
                        <RowDefinition Height="200"/>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="200"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
                    <DataGrid Name="dgShow" AutoGenerateColumns="False" SelectionUnit="CellOrRowHeader" Grid.Row="0" Grid.ColumnSpan="2">
                        <DataGrid.Columns>
                            <DataGridTextColumn Header="名稱"  Binding="{Binding [0]}"/>
                            <DataGridTextColumn Header="ID3V2"  Binding="{Binding [1]}"/>
                            <DataGridTextColumn Header="ID3V1"  Binding="{Binding [2]}"/>
                        </DataGrid.Columns>
                    </DataGrid>
                    <Image Name="imgCover" Grid.Row="1" Grid.Column="0"/>
                    <Grid Grid.Row="1" Grid.Column="1">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="1*"/>
                            <ColumnDefinition Width="1*"/>
                        </Grid.ColumnDefinitions>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="32"/>
                            <RowDefinition Height="*"/>
                        </Grid.RowDefinitions>
                        <Button Name="btnModify2" Content="修改 ID3V2" FontSize="18" Foreground="Navy" Grid.Row="1" Grid.Column="0" Margin="10" Click="btnModify2_Click"/>
                        <ComboBox Name="cmbGenre" Margin="10,5,10,2" Grid.Row="0" Grid.Column="1" SelectionChanged="cmbGenre_SelectionChanged"/>
                        <Button Name="btnModify1" Content="修改 ID3V1" FontSize="18" Grid.Row="1" Grid.Column="1" Margin="10" Click="btnModify1_Click"/>
                    </Grid>
                </Grid>
            </TabItem>
            <TabItem Header="批量">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="40"/>
                        <RowDefinition Height="*"/>
                    </Grid.RowDefinitions>
                    <Button Name="btnMuti" Content="批量讀取" FontSize="16" Margin="5" Grid.Row="0"/>
                    <DataGrid Name="dgMuti" Grid.Row="1">
                        <DataGrid.Columns>
                            <DataGridTextColumn Header="文件"  Binding="{Binding [0]}"/>
                            <DataGridTextColumn Header="Mpeg"  Binding="{Binding [1]}"/>
                            <DataGridTextColumn Header="Layer"  Binding="{Binding [2]}"/>
                            <DataGridTextColumn Header="波特率"  Binding="{Binding [3]}"/>
                            <DataGridTextColumn Header="頻率"  Binding="{Binding [4]}"/>
                            <DataGridTextColumn Header="聲道"  Binding="{Binding [5]}"/>
                        </DataGrid.Columns>
                    </DataGrid>
                </Grid>
            </TabItem>
        </TabControl>
    </Grid>
</Window>
View Code
using System.Windows;
using System.Windows.Controls;

namespace Mp3信息
{
    /// <summary>
    /// MainWindow.xaml 的交互邏輯
    /// </summary>
    public partial class MainWindow : Window
    {
        private string filteStr = "MP3 File|*.mp3|All File|*.*";
        private Mp3FileInfo mp3 = new Mp3FileInfo();

        public MainWindow()
        {
            InitializeComponent();
 
            dgShow.ItemsSource = mp3.Mp3Infos;
            cmbGenre.ItemsSource = mp3.Genres;
        }
        //---打開文件按鈕
        private void btnFile_Click(object sender, RoutedEventArgs e)
        {
            string filename = GetOpenFilePath(filteStr);
            if (!string.IsNullOrEmpty(filename))
            {
                txtFile.Text = filename;
                dgShow.BeginEdit();
                mp3.GetMp3Info(filename);
                dgShow.EndInit();
                if (mp3.CoverExist)
                {
                    imgCover.Source = mp3.CoverPicture;
                }
                cmbGenre.SelectedIndex =int.Parse(mp3.Mp3Infos[5][2]);
            }
        }
       //---取得打開文件名
        private string GetOpenFilePath(string filterstr)
        {
            var dlg = new Microsoft.Win32.OpenFileDialog();
            dlg.Filter = filterstr;
            if (dlg.ShowDialog() == true)
            {
                return dlg.FileName;
            }
            return "";
        }
        //---取得保存文件名
        private string GetSaveFilePath(string filterstr)
        {
            var dlg = new Microsoft.Win32.SaveFileDialog();
            //dlg.FileName = Path.GetFileNameWithoutExtension(memoFilePath);
            //dlg.DefaultExt = ".memo";
            dlg.Filter = filterstr;
            if (dlg.ShowDialog() == true)
            {
                return dlg.FileName;
            }
            return "";
        }

        private void btnModify1_Click(object sender, RoutedEventArgs e)
        {
                mp3.SetV1TagInfo(txtFile.Text);
        }

        private void cmbGenre_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            dgShow.BeginInit();
            mp3.Mp3Infos[5][2] = cmbGenre.SelectedIndex.ToString();
            dgShow.EndInit();
        }

        private void btnModify2_Click(object sender, RoutedEventArgs e)
        {
            mp3.SetV2TagInfo(txtFile.Text);
        }
    }
}
View Code
/******************************************************
 * MP3 音樂格式文件信息讀取
 * 做者:烏龍哈里
 * 最後修改:2017-03-07
 * 參考:
 * 一、http://id3.org/d3v2.3.0
 * 二、http://blog.csdn.net/alin0725/article/details/1876253
 * 三、http://www.mpgedit.org/mpgedit/mpeg%5Fformat/MP3Format.html
 * 四、https://en.wikipedia.org/wiki/MP3
 ******************************************************/
namespace Mp3信息
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.IO;
    using System.Linq;
    using System.Reflection;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Media.Imaging;


    /// <summary>
    /// 主程序class
    /// </summary>
    class Mp3FileInfo
    {
        public string Mp3File { get; set; }
        //注意:要先創建一個放置音樂類型的txt文件
        public string GenreFile { get; set; } = @".\mp3genre.txt";

        private int V1TagLength = 128;
        private int V2TagHeaderLength = 10;
        private string V1TagSymbol = "TAG";
        private string V2TagSymbol = "ID3";
        private string V2TagPictureId = "APIC";
        private int[] V1TagStruct = new int[14];//id3v1數據結構
        public string[] Genres;//音樂類型

        private string[] Mpeg;
        private string[] Layer;
        private string[] Bitrate;
        private string[] Hz;
        private string[] Channel;

        public ObservableCollection<string[]> Mp3Infos = new ObservableCollection<string[]>();
        public BitmapSource CoverPicture;
        public bool CoverExist = false;
        public int  NewCoverType = -1;
        private string[] V2TagFrameIds;

        //---初始化
        public Mp3FileInfo()
        {
            FillV1TagStruct();
            FillGenres();
            FillHeader();
            FillV2TagFrameIds();
        }
        //---批量取得信息(之後再寫)
        public void GetMutiInfo(string path)
        {

        }
        //---寫id3v2信息(有問題,寫成功後用windows的播放器播放正常,圖片也出現,但歌名等信息不出現)
        public void SetV2TagInfo(string path)
        {

            List<(string frameid, string content)> list = new List<(string, string)>();
            int n = 0;
            for (int i = 0; i < V2TagFrameIds.Length; i++)
            {
                if (Mp3Infos[i][1].Length > 0)
                {
                    list.Add((V2TagFrameIds[i],Mp3Infos[i][1]));
                    n += Mp3Infos[i][1].Length*2 + 3 + 10;
                }
            }
            n += 10;
            byte[] _data = new byte[n];
            Encoding.Default.GetBytes(V2TagSymbol,0,3,_data,0);
            _data[3] = 3;
            int m = 10;
            foreach (var info in list)
            {
                Encoding.Default.GetBytes(info.frameid,0,4,_data,m);
                int k = info.content.Length*2 + 3;
                _data[m + 4] = (byte)(k >>24);
                _data[m + 5] = (byte)(k >>16);
                _data[m + 6] = (byte)(k >> 8);
                _data[m + 7] = (byte)k;
                _data[m + 10] = 1;
                _data[m + 11] = 255;
                _data[m + 12] = 254;
                Encoding.Unicode.GetBytes(info.content,0,info.content.Length,_data,m+13);
                m =m+ k + 10;
            }
            m = n;
            if (NewCoverType > -1)
            {

            }
            else
            {
                using (FileStream fs=File.OpenRead(path))
                {
                    int _framelength = GetV2TagFrameLength(fs);
                    byte[] _framedata = new byte[_framelength];
                    fs.Read(_framedata, 0, _framedata.Length);
                    var _frames = GetV2TagFrameInfo(_framedata);
                    int _index = -1;
                    for (int i = 0; i < _frames.Count; i++)
                    {
                        if (string.Compare(_frames[i].frameid, V2TagPictureId) == 0)
                        {
                            n += _frames[i].length;
                            _index = i;
                            break;
                        }
                    }
                    n = n+ (int)fs.Length - _framelength - 10;
                    Array.Resize(ref _data, n);
                    int k = m;
                    if (_index > -1)
                    {
                        k = m + _frames[_index].length;
                        for(int i=0; i < _frames[_index].length; i++)
                        {
                           _data[m++]=_framedata[_frames[_index].start + i];
                        }   
                    }
                    _data[6] = (byte)((k >> 21)&0x7F);
                    _data[7] = (byte)((k >> 14) & 0x7F);
                    _data[8] = (byte)((k >> 7) & 0x7F);
                    _data[9] = (byte)(k & 0x7F);

                    fs.Read(_data, m, (int)fs.Length - _framelength - 10);

                }
            }
            using (FileStream fs = File.Create(@"d:\test\123.mp3"))
            {
                fs.Write(_data, 0, _data.Length);
            }

        }
        //---寫id3v1信息
        public void SetV1TagInfo(string path)
        {
            byte[] info = new byte[V1TagLength];
            info[0] = (byte)V1TagSymbol[0];
            info[1] = (byte)V1TagSymbol[1];
            info[2] = (byte)V1TagSymbol[2];
            for (int i = 0; i < 5; i++)
            {
                string s = Mp3Infos[i][2].Trim();
                Encoding.Default.GetBytes(s, 0, s.Length, info, V1TagStruct[(i + 1) * 2]);
            }
            info[V1TagStruct[12]] = byte.Parse(Mp3Infos[5][2]);
            using (FileStream fs = File.OpenWrite(path))
            {
                fs.Seek(-info.Length, SeekOrigin.End);
                fs.Write(info, 0, info.Length);
            }
        }
        //---讀取mp3信息
        public void GetMp3Info(string path)
        {
            Mp3Infos.Clear();
            FillMp3Infos();
            using (FileStream fs = File.OpenRead(path))
            {
                GetV1TagInfo(fs);
                int _v2TagLength = GetV2TagFrameLength(fs);
                if (_v2TagLength > 0)
                {
                    GetV2TagInfo(fs, _v2TagLength);
                    int[] _index = new int[5];
                    int n = V2TagFrameIds.Length;
                    GetMp3HeaderInfo(_index, fs, _v2TagLength);
                    Mp3Infos[n][1] = Mpeg[_index[0]];
                    Mp3Infos[n+1][1] = Layer[_index[1]];
                    Mp3Infos[n+2][1] = Bitrate[_index[2]];
                    Mp3Infos[n+3][1] = Hz[_index[3]];
                    Mp3Infos[n+4][1] = Channel[_index[4]];
                }
            }
        }
        //---讀取mp3 header 信息
        private void GetMp3HeaderInfo(int[] Index, FileStream fs, int Id3v2TagFrameLength)
        {
            byte[] _header = new byte[3];
            Func<bool> FindHeader = () =>
             {
                 int m = 1024;
                 int start = 0;
                 fs.Seek(Id3v2TagFrameLength + V2TagHeaderLength, SeekOrigin.Begin);
                 while (start++ < m)
                 {
                     if (fs.ReadByte() == 255)
                     {
                         fs.Read(_header, 0, 3);
                         return true;
                     }
                 }
                 return false;

             };
            if (FindHeader())
            {
                int _mpegIndex = (_header[0] >> 3) & Convert.ToByte("00000011", 2);
                int _layerIndex = (_header[0] >> 1) & Convert.ToByte("00000011", 2);
                int _bitrateIndex = _header[1] >> 4;
                int _hzIndex = (_header[1] >> 2) & Convert.ToByte("00000011", 2);
                int _channelIndex = _header[2] >> 6;
                int _bitrateIndexStep = _mpegIndex * 48 + (_layerIndex - 1) * 16;
                int _hzIndexStep = _mpegIndex * 4;
                Index[0] = _mpegIndex;
                Index[1] = _layerIndex;
                Index[2] = _bitrateIndex + _bitrateIndexStep;
                Index[3] = _hzIndex + _hzIndexStep;
                Index[4] = _channelIndex;
            }
        }
        //---讀取id3v2標記內容
        private void GetV2TagInfo(FileStream fs, int Length)
        {
            CoverExist = false;
            NewCoverType = -1;
            byte[] _v2tag = new byte[Length];
            fs.Seek(V2TagHeaderLength, SeekOrigin.Begin);
            fs.Read(_v2tag, 0, _v2tag.Length);
            var _frames = GetV2TagFrameInfo(_v2tag);
            foreach (var _frame in _frames)
            {
                int _index = GetV2TagFrameIdIndex(_frame.frameid);
                if (_index > -1)
                {
                    Mp3Infos[_index][1] = GetFrameStrContent(_v2tag, _frame.start + 10, _frame.length - 10);
                }
                else
                {
                    //若是是APIC,則讀取圖片
                    if (string.Compare(_frame.frameid, V2TagPictureId) == 0)
                    {
                        GetImage(_v2tag, _frame.start + 10, _frame.length - 10);
                    }
                }

            }
        }
        //---讀取圖片
        private void GetImage(byte[] source, int start, int contentLength)
        {
            //尋找圖片位置
            Func<byte[], (bool found, int startpos)> FindImage = symbol =>
                {
                    int n = start;
                    int m = start + 30;
                    while (n < m)
                    {
                        if (n > m - symbol.Length)
                        {
                            return (false, -1);
                        }
                        if (source[n] == symbol[0] && source[n + 1] == symbol[1] && source[n + 2] == symbol[2])
                        {
                            return (true, n);
                        }
                        n++;
                    }
                    return (false, -1);
                };
            //取得圖片信息
            Func<(int ImageKind, int startpos)> GetImageInfo = () =>
             {
                 byte[] _imghead = new byte[3];
                 //jpeg header
                 _imghead[0] = 0xFF;
                 _imghead[1] = 0xD8;
                 _imghead[2] = 0xFF;
                 var t = FindImage(_imghead);
                 if (t.found)
                 {
                     return (0, t.startpos);
                 }
                 //png header
                 _imghead[0] = 0x89;
                 _imghead[1] = 0x50;
                 _imghead[2] = 0x4E;
                 t = FindImage(_imghead);
                 if (t.found)
                 {
                     return (1, t.startpos);
                 }
                 return (-1, -1);
             };
            //讀取圖片
            var p = GetImageInfo();
            if (p.ImageKind > -1)
            {
                CoverExist = true;
                MemoryStream ms = new MemoryStream();
                ms.Write(source, p.startpos, contentLength + start - 10 - p.startpos);
                ms.Seek(0, SeekOrigin.Begin);
                switch (p.ImageKind)
                {
                    case 0:
                        JpegBitmapDecoder jpeg = new JpegBitmapDecoder(ms, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
                        CoverPicture = jpeg.Frames[0];
                        break;
                    case 1:
                        PngBitmapDecoder png = new PngBitmapDecoder(ms, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
                        CoverPicture = png.Frames[0];
                        break;
                }
            }

        }
        //---讀取v2 Frame string內容
        private string GetFrameStrContent(byte[] source, int start, int length)
        {
            if (source[start + 1] == 255 && source[start + 2] == 254)
            {
                return Encoding.Unicode.GetString(source, start + 3, length - 3);
            }
            if (source[start + 1] == 254 && source[start + 2] == 255)
            {
                return Encoding.BigEndianUnicode.GetString(source, start + 3, length - 3);
            }

            return Encoding.Default.GetString(source, start + 1, length - 1);
        }
        //---根據V2TagFrameIds,找出FrameId在mp3infos的index
        private int GetV2TagFrameIdIndex(string FrameId)
        {
            for (int i = 0; i < V2TagFrameIds.Length; i++)
            {
                if (string.Compare(V2TagFrameIds[i], FrameId) == 0)
                {
                    return i;
                }
            }
            return -1;
        }
        //---讀取v2tag frame 信息
        private List<(string frameid, int start, int length)> GetV2TagFrameInfo(byte[] FrameData)
        {
            int n = 0;
            List<(string frameid, int length, int start)> _frames = new List<(string frameid, int length, int start)>();
            while (n < FrameData.Length - 10)
            {
                int _length = FrameData[n + 4] << 24 | FrameData[n + 5] << 16 | FrameData[n + 6] << 8 | FrameData[n + 7];
                if (_length > 0)
                {
                    _frames.Add((Encoding.Default.GetString(FrameData, n, 4), n, _length + 10));
                    n += _length;

                }
                n += 10;
            }
            return _frames;
        }
        //---判斷 id3v2標誌是否存在,並計算大小
        private int GetV2TagFrameLength(FileStream fs)
        {
            fs.Seek(0, SeekOrigin.Begin);
            byte[] _head = new byte[V2TagHeaderLength];
            fs.Read(_head, 0, _head.Length);
            if (string.Compare(Encoding.Default.GetString(_head, 0, 3), V2TagSymbol) == 0)
            {
                return _head[6] << 21 | _head[7] << 14 | _head[8] << 7 | _head[9];
            }
            return 0;
        }
        //---讀取id3v1 Tag 信息
        private void GetV1TagInfo(FileStream fs)
        {
            //取得ascii編碼的字符串截止到 0 的數據長度
            Func<byte[], int, int, int> GetStringDataLength = (source, start, length) =>
               {
                   for (int i = 0; i < length; i++)
                   {
                       if (source[start + i] == 0)
                       {
                           return i;
                       }
                   }
                   return length;
               };

            byte[] _v1Tag = new byte[V1TagLength];
            fs.Seek(-_v1Tag.Length, SeekOrigin.End);
            fs.Read(_v1Tag, 0, _v1Tag.Length);
            if (string.Compare(Encoding.Default.GetString(_v1Tag, V1TagStruct[0], V1TagStruct[1]), V1TagSymbol) == 0)
            {
                for (int i = 0; i < 5; i++)
                {
                    Mp3Infos[i][2] = Encoding.Default.GetString(_v1Tag, V1TagStruct[(i + 1) * 2],
                        GetStringDataLength(_v1Tag, V1TagStruct[(i + 1) * 2], V1TagStruct[(i + 1) * 2 + 1]));

                }
                Mp3Infos[5][2] = _v1Tag[V1TagStruct[12]].ToString();
            }
        }
        //---填充id3v2Tag Frame 標誌
        private void FillV2TagFrameIds()
        {
            V2TagFrameIds = new string[]{
                "TIT2","TPE1","TALB","TYER","COMM","TCON",
                "TPE2","TCOM","TPE3","TPE4","TRCK","TCOP"
            };
        }
        //---填充Mp3infos
        private void FillMp3Infos()
        {

            Mp3Infos.Add(new string[] { "歌名", "", "" });
            Mp3Infos.Add(new string[] { "表演", "", "" });
            Mp3Infos.Add(new string[] { "專輯", "", "" });
            Mp3Infos.Add(new string[] { "年份", "", "" });
            Mp3Infos.Add(new string[] { "備註", "", "" });
            Mp3Infos.Add(new string[] { "種類", "", "" });
            //如下爲id3v2tag增長
            Mp3Infos.Add(new string[] { "樂隊", "", "" });
            Mp3Infos.Add(new string[] { "做曲", "", "" });
            Mp3Infos.Add(new string[] { "指揮", "", "" });
            Mp3Infos.Add(new string[] { "重編", "", "" });
            Mp3Infos.Add(new string[] { "音軌", "", "" });
            Mp3Infos.Add(new string[] { "版權", "", "" });

            //如下爲mp3數據頭
            Mp3Infos.Add(new string[] { "Mpeg", "", "" });
            Mp3Infos.Add(new string[] { "Layer", "", "" });
            Mp3Infos.Add(new string[] { "波特率", "", "" });
            Mp3Infos.Add(new string[] { "頻率", "", "" });
            Mp3Infos.Add(new string[] { "聲道", "", "" });
        }
        //填充mp3數據頭的數據表
        private void FillHeader()
        {
            Mpeg = new string[] { "MPEG 2.5", "Reserved", "MPEG 2", "MPEG 1" };
            Layer = new string[] { "Reserved", "Layer III", "Layer II", "Layer I" };
            Bitrate = new string[]
            {
                "free","8","16","24","32","40","48","56","64","80","96","112","128","144","160","bad",
                "free","8","16","24","32","40","48","56","64","80","96","112","128","144","160","bad",
                "free","32","48","56","64","80","96","112","128","144","160","176","192","224","256","bad",

                "free","0","0","0","0","0","0","0","0","0","0","0","0","0","0","bad",
                "free","0","0","0","0","0","0","0","0","0","0","0","0","0","0","bad",
                "free","0","0","0","0","0","0","0","0","0","0","0","0","0","0","bad",

                "free","8","16","24","32","40","48","56","64","80","96","112","128","144","160","bad",
                "free","8","16","24","32","40","48","56","64","80","96","112","128","144","160","bad",
                "free","32","48","56","64","80","96","112","128","144","160","176","192","224","256","bad",

                "free","32","40","48","56","64","80","96","112","128","160","192","224","256","320","bad",
                "free","32","48","56","64","80","96","112","128","160","192","224","256","320","384","bad",
                "free","32","64","96","128","160","192","224","256","288","320","352","384","416","448","bad",

            };

            Hz = new string[]
            {
                "11025","12000","8000","Reserved",
                "0","0","0","Reserved",
                "22050","24000","16000","Reserved",
                "44100","48000","32000","Reserved"
            };
            /*「聯合立體聲模式」是音頻編碼的立體聲模式之一。聯合立體聲模式充分利用左右聲道的類似之處,
             * 對於左右聲道的相同部分再也不重複編碼,減小了數據的浪費,這樣就能夠作到在較低的位率下表現更豐富的細節。
             * 對於左右聲道差別不大的音頻來講,聯合立體聲編碼模式一般在較低的位率下就能夠獲得不錯的效果。
             * 而「立體聲模式」則使用兩個相互獨立的聲道進行編碼,所以它須要較多的位率,但它的左右聲道的分離度較高,
             * 一般使用在位率較高的場合,用於高質量的音頻編碼。
             */
            Channel = new string[] { "立體聲", "聯合立體聲", "雙聲道", "單聲道" };
        }
        //---填充音樂類型表
        private void FillGenres()
        {
            string[] str = File.ReadAllText(GenreFile).Split(new char[] { (char)13, (char)10, '.' }, StringSplitOptions.RemoveEmptyEntries);
            Genres = new string[str.Length / 2];
            for (int i = 1; i < str.Length; i += 2)
            {
                Genres[(i - 1) / 2] = str[i];
            }
        }
        //---填充 Id3v1 數據結構
        private void FillV1TagStruct()
        {
            //symbol
            V1TagStruct[0] = 0;//start pos
            V1TagStruct[1] = 3;//length
            //song title
            V1TagStruct[2] = 3;
            V1TagStruct[3] = 30;
            //artist
            V1TagStruct[4] = 33;
            V1TagStruct[5] = 30;
            //album
            V1TagStruct[6] = 63;
            V1TagStruct[7] = 30;
            //year
            V1TagStruct[8] = 93;
            V1TagStruct[9] = 4;
            //comment
            V1TagStruct[10] = 97;
            V1TagStruct[11] = 30;
            //genre
            V1TagStruct[12] = 127;
            V1TagStruct[13] = 1;
        }
    }
}
View Code
//mp3genre.txt
      0.Blues
      1.Classic Rock
      2.Country
      3.Dance
      4.Disco
      5.Funk
      6.Grunge
      7.Hip-Hop
      8.Jazz
      9.Metal
     10.New Age
     11.Oldies
     12.Other
     13.Pop
     14.R&B
     15.Rap
     16.Reggae
     17.Rock
     18.Techno
     19.Industrial
     20.Alternative
     21.Ska
     22.Death Metal
     23.Pranks
     24.Soundtrack
     25.Euro-Techno
     26.Ambient
     27.Trip-Hop
     28.Vocal
     29.Jazz+Funk
     30.Fusion
     31.Trance
     32.Classical
     33.Instrumental
     34.Acid
     35.House
     36.Game
     37.Sound Clip
     38.Gospel
     39.Noise
     40.AlternRock
     41.Bass
     42.Soul
     43.Punk
     44.Space
     45.Meditative
     46.Instrumental Pop
     47.Instrumental Rock
     48.Ethnic
     49.Gothic
     50.Darkwave
     51.Techno-Industrial
     52.Electronic
     53.Pop-Folk
     54.Eurodance
     55.Dream
     56.Southern Rock
     57.Comedy
     58.Cult
     59.Gangsta
     60.Top 40
     61.Christian Rap
     62.Pop/Funk
     63.Jungle
     64.Native American
     65.Cabaret
     66.New Wave
     67.Psychadelic
     68.Rave
     69.Showtunes
     70.Trailer
     71.Lo-Fi
     72.Tribal
     73.Acid Punk
     74.Acid Jazz
     75.Polka
     76.Retro
     77.Musical
     78.Rock & Roll
     79.Hard Rock
     80.Folk
     81.Folk-Rock
     82.National Folk
     83.Swing
     84.Fast Fusion
     85.Bebob
     86.Latin
     87.Revival
     88.Celtic
     89.Bluegrass
     90.Avantgarde
     91.Gothic Rock
     92.Progressive Rock
     93.Psychedelic Rock
     94.Symphonic Rock
     95.Slow Rock
     96.Big Band
     97.Chorus
     98.Easy Listening
     99.Acoustic
    100.Humour
    101.Speech
    102.Chanson
    103.Opera
    104.Chamber Music
    105.Sonata
    106.Symphony
    107.Booty Bass
    108.Primus
    109.Porn Groove
    110.Satire
    111.Slow Jam
    112.Club
    113.Tango
    114.Samba
    115.Folklore
    116.Ballad
    117.Power Ballad
    118.Rhythmic Soul
    119.Freestyle
    120.Duet
    121.Punk Rock
    122.Drum Solo
    123.Acapella
    124.Euro-House
    125.Dance Hall
View Code
相關文章
相關標籤/搜索