MP3 信息讀取html
運行環境:Window7 64bit,.NetFramework4.61,C# 7.0; 編者:烏龍哈里 2017-03-13算法
參考:express
章節:windows
正文:數據結構
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>
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); } } }
/****************************************************** * 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; } } }
//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