C# :: Aufgabe #220
2 Lösungen

Lesen und Bearbeiten von MP3-Dateien
Anfänger - C#
von Exception
- 14.07.2018 um 08:28 Uhr
Hallo zusammen,
heute sollt ihr Informationen aus MP3-Dateien lesen und editieren.
Dafür sollt ihr eine Windows Forms Anwendung schreiben,
in der ihr per Klick auf einen Button eine MP3-Datei einlesen und nach der Bearbeitung wieder speichern könnt.
Die folgenden Informationen sollen ausgelesen werden:
- Titel des Stücks (30)
- Interpret (30)
- Album / CD-Titel (30)
- Erscheinungsjahr (4)
- Kommentar (30)
- Genre (1)
Diese Informationen ("ID3-Tags") liegen als Zeichenketten in den letzten 125 Byte der Datei.
Die in der Klammer stehende Zahl zeigt an, wieviel Byte für die entsprechende Information belegt sind.
Doch zuvor muss geprüft werden ob die Datei auch wirklich eine gültige MP3-Datei ist.
Diese Information beginnt im 128. Byte und ist insg. 3 Byte lang.
(D.h., dass der komplette ID3-Tag 128 Byte lang ist)
In diesen 3 Byte muss "TAG" stehen (= TAG-Identifizierung), wenn nicht wird eine Exception o.ä. geworfen - ist euer Bier.
(Sicherlich kann es vorkommen, dass bei einer anderen Datei, genau an dieser Stelle ebenfalls "TAG" steht, aber für die Einfachkeit belassen wir es hierbei)
Wenn die Datei eingelesen ist und z.B. in Textboxen die Informationen ausgegeben wurden können diese bearbeitet werden und mit einem anderen Button gesichert / geschrieben werden.
Viel Spaß! :)
Hilfe / Nützliches:
- BinaryReader
- BinaryWriter
heute sollt ihr Informationen aus MP3-Dateien lesen und editieren.
Dafür sollt ihr eine Windows Forms Anwendung schreiben,
in der ihr per Klick auf einen Button eine MP3-Datei einlesen und nach der Bearbeitung wieder speichern könnt.
Die folgenden Informationen sollen ausgelesen werden:
- Titel des Stücks (30)
- Interpret (30)
- Album / CD-Titel (30)
- Erscheinungsjahr (4)
- Kommentar (30)
- Genre (1)
Diese Informationen ("ID3-Tags") liegen als Zeichenketten in den letzten 125 Byte der Datei.
Die in der Klammer stehende Zahl zeigt an, wieviel Byte für die entsprechende Information belegt sind.
Doch zuvor muss geprüft werden ob die Datei auch wirklich eine gültige MP3-Datei ist.
Diese Information beginnt im 128. Byte und ist insg. 3 Byte lang.
(D.h., dass der komplette ID3-Tag 128 Byte lang ist)
In diesen 3 Byte muss "TAG" stehen (= TAG-Identifizierung), wenn nicht wird eine Exception o.ä. geworfen - ist euer Bier.
(Sicherlich kann es vorkommen, dass bei einer anderen Datei, genau an dieser Stelle ebenfalls "TAG" steht, aber für die Einfachkeit belassen wir es hierbei)
Wenn die Datei eingelesen ist und z.B. in Textboxen die Informationen ausgegeben wurden können diese bearbeitet werden und mit einem anderen Button gesichert / geschrieben werden.
Viel Spaß! :)
Hilfe / Nützliches:
- BinaryReader
- BinaryWriter
Lösungen:
Ich habe für die MP3-Dateien zwei verschiedene Klassen (und eine Basisklasse) erstellt.
Die Klasse MP3FileID3v1 entspricht der Aufgabenstellung und sollte theoretisch funktionieren. Da laut Aufgabenstellung die erste Version der ID3-Tags verlangt wird und MP3-Dateien heute noch andere Informationen (z.B. Cover, Albuminterpret, uvm.) beinhalten und der Tag anders aufgebaut ist, habe ich noch die Klasse MP3FileID3v2 erstellt. In dem Programm habe ich nur die Klasse MP3FileID3v2 genutzt.
MainWindow.xaml.cs
C#-Code
MainWindow.xaml
XML-Code
Basisklasse MP3File
C#-Code
Klasse MP3FileID3v1 (nicht getestet, da ich keine MP3-Dateien mit ID3v1-Tag habe)
C#-Code
Klasse MP3ID3v2 (benötigt Verweis auf TagLib)
https://www.nuget.org/packages/taglib/
C#-Code
Die Klasse MP3FileID3v1 entspricht der Aufgabenstellung und sollte theoretisch funktionieren. Da laut Aufgabenstellung die erste Version der ID3-Tags verlangt wird und MP3-Dateien heute noch andere Informationen (z.B. Cover, Albuminterpret, uvm.) beinhalten und der Tag anders aufgebaut ist, habe ich noch die Klasse MP3FileID3v2 erstellt. In dem Programm habe ich nur die Klasse MP3FileID3v2 genutzt.
MainWindow.xaml.cs

using System; using System.Collections.ObjectModel; using System.IO; using System.Windows; using System.Windows.Controls; using System.Windows.Forms; namespace WpfMP3Editor { /// <summary> /// Interaktionslogik für MainWindow.xaml /// </summary> public partial class MainWindow : Window { static readonly string directory = $@"C:\Users\{Environment.UserName}\Music"; SaveFileDialog sfd; OpenFileDialog ofd; public MainWindow() { InitializeComponent(); sfd = new SaveFileDialog(); sfd.AddExtension = true; sfd.DefaultExt = ".jpg"; sfd.Filter = "JPEG-Dateien(*.JPG)|*.JPG"; ofd = new OpenFileDialog(); ofd.Filter = "Bild-Dateien(*.BMP;*.JPG;*.GIF;*.PNG;*.TIFF)|*.BMP;*.JPG;*.GIF;*.PNG;*.TIFF"; } private void Window_Loaded(object sender, RoutedEventArgs e) { System.Windows.Data.CollectionViewSource mP3FileID3v2ViewSource = ((System.Windows.Data.CollectionViewSource)(this.FindResource("mP3FileID3v2ViewSource"))); // Laden Sie Daten durch Festlegen der CollectionViewSource.Source-Eigenschaft: mP3FileID3v2ViewSource.Source = new ObservableCollection<MP3FileID3v2>(MP3FileID3v2.GetAllMP3Files(directory)); } private void mP3FileID3v2DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e) { foreach (var item in e.RemovedItems) { if (item is MP3File) { MP3File mp3 = (MP3File)item; mp3.Save(); } } if (e.RemovedItems.Count > 0) { mP3FileID3v2DataGrid.Items.Refresh(); } } private void menuItemSave_Click(object sender, RoutedEventArgs e) { MP3FileID3v2 mp3 = (MP3FileID3v2)mP3FileID3v2DataGrid.SelectedItem; if (mp3.Pictures.Length > 0 && sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK) { byte[] pic = mp3.Pictures[0]; using (MemoryStream ms = new MemoryStream(pic)) { using (System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(ms)) { bitmap.Save(sfd.FileName, System.Drawing.Imaging.ImageFormat.Jpeg); } } } } private void menuItemChange_Click(object sender, RoutedEventArgs e) { MP3FileID3v2 mp3 = (MP3FileID3v2)mP3FileID3v2DataGrid.SelectedItem; if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK) { using (System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(ofd.FileName)) { using (MemoryStream ms = new MemoryStream()) { bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg); if (mp3.Pictures.Length == 0) { mp3.Pictures = new byte[1][]; } mp3.Pictures[0] = ms.ToArray(); mP3FileID3v2DataGrid.Items.Refresh(); } } } } } }
MainWindow.xaml

<Window x:Class="WpfMP3Editor.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:WpfMP3Editor" xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase" mc:Ignorable="d" Title="MainWindow" Height="550" Width="825" Loaded="Window_Loaded"> <Window.Resources> <CollectionViewSource x:Key="mP3FileID3v2ViewSource" d:DesignSource="{d:DesignInstance {x:Type local:MP3FileID3v2}, CreateList=True}"> <CollectionViewSource.GroupDescriptions> <PropertyGroupDescription PropertyName="Album"/> </CollectionViewSource.GroupDescriptions> <CollectionViewSource.SortDescriptions> <scm:SortDescription PropertyName="Disc"/> <scm:SortDescription PropertyName="TitelNum"/> </CollectionViewSource.SortDescriptions> </CollectionViewSource> </Window.Resources> <Grid DataContext="{StaticResource mP3FileID3v2ViewSource}"> <DataGrid x:Name="mP3FileID3v2DataGrid" AutoGenerateColumns="False" EnableRowVirtualization="True" ItemsSource="{Binding}" Margin="0" RowDetailsVisibilityMode="VisibleWhenSelected" CanUserAddRows="False" CanUserDeleteRows="False" IsReadOnly="False" SelectionMode="Single" SelectionChanged="mP3FileID3v2DataGrid_SelectionChanged"> <DataGrid.Columns> <DataGridTextColumn x:Name="titelColumn" Binding="{Binding Titel, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True, BindsDirectlyToSource=True}" Header="Titel" Width="SizeToCells"/> <DataGridTextColumn x:Name="interpretColumn" Binding="{Binding Interpret, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True, BindsDirectlyToSource=True}" Header="Interpret" Width="SizeToCells"/> <DataGridTextColumn x:Name="albumColumn" Binding="{Binding Album, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True, BindsDirectlyToSource=True}" Header="Album" Width="SizeToCells"/> <DataGridTextColumn x:Name="releaseYearColumn" Binding="{Binding ReleaseYear, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True, BindsDirectlyToSource=True}" Header="Jahr" Width="SizeToCells"/> <DataGridTextColumn x:Name="commentColumn" Binding="{Binding Comment, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True, BindsDirectlyToSource=True}" Header="Kommentar" Width="SizeToCells"/> <DataGridTextColumn x:Name="genreColumn" Binding="{Binding Genre, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True, BindsDirectlyToSource=True}" Header="Genre" Width="SizeToCells"/> </DataGrid.Columns> <DataGrid.RowDetailsTemplate> <DataTemplate> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <Image Source="{Binding GetBitmapImage, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True, BindsDirectlyToSource=True}" Width="128" Height="128" Margin="0,0" Grid.Column="0"> <Image.ContextMenu> <ContextMenu> <MenuItem x:Name="menuItemSave" Header="Bild speichern" Click="menuItemSave_Click"/> <MenuItem x:Name="menuItemChange" Header="Bild ändern" Click="menuItemChange_Click"/> </ContextMenu> </Image.ContextMenu> </Image> <Grid Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="20,0,0,0"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <TextBlock Margin="0,3,0,0" FontWeight="Bold" Text="CD-Nr" Grid.Row="0"/> <TextBox Text="{Binding Disc, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True, BindsDirectlyToSource=True}" Margin="100,0,0,0" Grid.Row="0" HorizontalAlignment="Left" VerticalAlignment="Top" Width="100" TextAlignment="Right"/> <TextBlock FontWeight="Bold" Text="Titel-Nr" Grid.Row="1"/> <TextBox Text="{Binding TitelNum, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True, BindsDirectlyToSource=True}" Margin="100,0,0,0" Grid.Row="1" HorizontalAlignment="Left" VerticalAlignment="Top" Width="100" TextAlignment="Right"/> <TextBlock FontWeight="Bold" Text="Jahr" Grid.Row="2"/> <TextBox Text="{Binding ReleaseYear, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True, BindsDirectlyToSource=True}" Margin="100,0,0,0" Grid.Row="2" HorizontalAlignment="Left" VerticalAlignment="Top" Width="100" TextAlignment="Right"/> <TextBlock FontWeight="Bold" Text="Genre" Grid.Row="3"/> <TextBox Text="{Binding Genre, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True, BindsDirectlyToSource=True}" Margin="100,0,0,0" Grid.Row="3" HorizontalAlignment="Left" VerticalAlignment="Top" Width="100" TextAlignment="Right"/> <TextBlock FontWeight="Bold" Text="Dauer" Grid.Row="4"/> <TextBox Text="{Binding Duration, Mode=OneWay}" Margin="100,0,0,0" Grid.Row="4" HorizontalAlignment="Left" VerticalAlignment="Top" Width="100" TextAlignment="Right" IsReadOnly="True"/> <TextBlock FontWeight="Bold" Text="Copyright" Grid.Row="5"/> <TextBox Text="{Binding Copyright, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True, BindsDirectlyToSource=True}" Margin="100,0,0,0" Grid.Row="5" HorizontalAlignment="Left" VerticalAlignment="Top" Width="100" TextAlignment="Right"/> </Grid> <Grid Grid.Column="2" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="20,0,0,0"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <TextBlock Margin="0,3,0,0" FontWeight="Bold" Text="Album" Grid.Row="0"/> <TextBox Text="{Binding Album, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True, BindsDirectlyToSource=True}" Margin="100,0,0,0" Grid.Row="0" HorizontalAlignment="Left" VerticalAlignment="Top" Width="100" TextAlignment="Right"/> <TextBlock FontWeight="Bold" Text="Titel" Grid.Row="1"/> <TextBox Text="{Binding Titel, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True, BindsDirectlyToSource=True}" Margin="100,0,0,0" Grid.Row="1" HorizontalAlignment="Left" VerticalAlignment="Top" Width="100" TextAlignment="Right"/> <TextBlock FontWeight="Bold" Text="Interpret" Grid.Row="2"/> <TextBox Text="{Binding Interpret, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True, BindsDirectlyToSource=True}" Margin="100,0,0,0" Grid.Row="2" HorizontalAlignment="Left" VerticalAlignment="Top" Width="100" TextAlignment="Right"/> <TextBlock FontWeight="Bold" Text="Albuminterpret" Grid.Row="3"/> <TextBox Text="{Binding AlbumInterpret, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True, BindsDirectlyToSource=True}" Margin="100,0,0,0" Grid.Row="3" HorizontalAlignment="Left" VerticalAlignment="Top" Width="100" TextAlignment="Right"/> <TextBlock FontWeight="Bold" Text="Komponist" Grid.Row="4"/> <TextBox Text="{Binding Composer, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True, BindsDirectlyToSource=True}" Margin="100,0,0,0" Grid.Row="4" HorizontalAlignment="Left" VerticalAlignment="Top" Width="100" TextAlignment="Right" IsReadOnly="True"/> <TextBlock FontWeight="Bold" Text="Kommentar" Grid.Row="5"/> <TextBox Text="{Binding Comment, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True, BindsDirectlyToSource=True}" Margin="100,0,0,0" Grid.Row="5" HorizontalAlignment="Left" VerticalAlignment="Top" Width="100" TextAlignment="Right"/> </Grid> </Grid> </DataTemplate> </DataGrid.RowDetailsTemplate> </DataGrid> </Grid> </Window>
Basisklasse MP3File

namespace WpfMP3Editor { public abstract class MP3File { public virtual string Filename { get; set; } public virtual string Titel { get; set; } public virtual string Interpret { get; set; } public virtual string Album { get; set; } public virtual uint ReleaseYear { get; set; } public virtual string Genre { get; set; } public virtual string Comment { get; set; } protected long fileSize; public virtual long FileSize => fileSize; public abstract void Save(); protected MP3File(string filename) { Filename = filename; } } }
Klasse MP3FileID3v1 (nicht getestet, da ich keine MP3-Dateien mit ID3v1-Tag habe)

using System; using System.IO; using System.Text; namespace WpfMP3Editor { public class MP3FileID3v1 : MP3File { static readonly Encoding Latin1 = Encoding.GetEncoding("ISO 8859-1"); static readonly byte[] TAG = Latin1.GetBytes("TAG"); private byte[] data; public byte[] Data => data; private byte[] titel; public override string Titel { get { return Latin1.GetString(titel).Trim(); } set { string v = value.PadRight(30, ' ').Substring(0, 30); titel = Latin1.GetBytes(v); } } private byte[] interpret; public override string Interpret { get { return Latin1.GetString(interpret).Trim(); } set { string v = value.PadRight(30, ' ').Substring(0, 30); interpret = Latin1.GetBytes(v); } } private byte[] album; public override string Album { get { return Latin1.GetString(album); } set { string v = value.PadRight(30, ' ').Substring(0, 30); album = Latin1.GetBytes(v); } } private byte[] releaseYear; public override uint ReleaseYear { get { return uint.Parse(Latin1.GetString(releaseYear)); } set { string v = value.ToString().PadLeft(4, '0'); releaseYear = Latin1.GetBytes(v); } } private byte[] comment; public override string Comment { get { return Latin1.GetString(comment).Trim(); } set { string v = value.PadRight(30, ' ').Substring(0, 30); comment = Latin1.GetBytes(v); } } private byte[] genre; public override string Genre { get { return Latin1.GetString(genre).Trim(); } set { string v = value.PadLeft(1, ' ').Substring(0, 1); genre = Latin1.GetBytes(v); } } private MP3FileID3v1(byte[] data, string filename) : base(filename) { this.data = data; } public override void Save() { using (FileStream fs = File.Create(Filename)) { fs.Write(data, 0, data.Length); fs.Write(TAG, 0, TAG.Length); fs.Write(titel, 0, titel.Length); fs.Write(interpret, 0, interpret.Length); fs.Write(album, 0, album.Length); fs.Write(releaseYear, 0, releaseYear.Length); fs.Write(comment, 0, comment.Length); fs.Write(genre, 0, genre.Length); } } public static MP3File Read(string filename) { using (FileStream fs = new FileStream(filename, FileMode.Open)) { byte[] data = new byte[fs.Length - 128]; byte[] tag = new byte[3]; byte[] titel = new byte[30]; byte[] interpret = new byte[30]; byte[] album = new byte[30]; byte[] releaseYear = new byte[4]; byte[] kommentar = new byte[30]; byte[] genre = new byte[1]; fs.Read(data, 0, data.Length); fs.Read(tag, 0, tag.Length); fs.Read(titel, 0, titel.Length); fs.Read(interpret, 0, interpret.Length); fs.Read(album, 0, album.Length); fs.Read(releaseYear, 0, releaseYear.Length); fs.Read(genre, 0, genre.Length); if (Latin1.GetString(tag) == "TAG") { MP3FileID3v1 mp3 = new MP3FileID3v1(data, filename); mp3.Titel = Latin1.GetString(titel); mp3.Interpret = Latin1.GetString(interpret); mp3.Album = Latin1.GetString(album); mp3.ReleaseYear = uint.Parse(Latin1.GetString(titel)); mp3.Comment = Latin1.GetString(kommentar); mp3.Genre = Latin1.GetString(genre); return mp3; } else { throw new ArgumentException("Datei ist keine gültige MP3-Datei mit ID3v1-Tag"); } } } } }
Klasse MP3ID3v2 (benötigt Verweis auf TagLib)
https://www.nuget.org/packages/taglib/

using System; using System.Collections.Generic; using System.Linq; using System.Windows.Media.Imaging; using TagLib; using FileInfo = System.IO.FileInfo; namespace WpfMP3Editor { public class MP3FileID3v2 : MP3File { public const string unknown = "Unbekannt"; public byte[][] Pictures { get; set; } public uint Disc { get; set; } public uint TitelNum { get; set; } private TimeSpan duration; public TimeSpan Duration => duration; public string[] TitelInterpret { get; set; } public string[] Genres { get; set; } public string[] Composers { get; set; } public string[] AlbumInterprets { get; set; } public string Copyright { get; set; } public BitmapImage GetBitmapImage { get { if (Pictures.Length > 0) { using (System.IO.MemoryStream ms = new System.IO.MemoryStream(Pictures[0])) { ms.Position = 0; BitmapImage image = new BitmapImage(); image.BeginInit(); image.CacheOption = BitmapCacheOption.OnLoad; image.CreateOptions = BitmapCreateOptions.PreservePixelFormat; image.StreamSource = ms; image.EndInit(); image.Freeze(); return image; } } else { return new BitmapImage(); } } } public override string Interpret { get { string ret = ""; foreach (string s in TitelInterpret) { ret += s + "; "; } if (ret == "") { return unknown; } ret = ret.Substring(0, ret.Length - 2); return ret; } set { if (value == unknown) { TitelInterpret = new string[0]; } else { string[] split = value.Split(';'); TitelInterpret = new string[split.Length]; for (int i = 0; i < split.Length; i++) { TitelInterpret[i] = split[i].Trim(); } } } } public override string Genre { get { string ret = ""; foreach (string s in Genres) { ret += s + "/"; } if (ret == "") { return unknown; } ret = ret.Substring(0, ret.Length - 1); return ret; } set { if (value == unknown) { Genres = new string[0]; } else { string[] split = value.Split('/'); Genres = new string[split.Length]; for (int i = 0; i < split.Length; i++) { Genres[i] = split[i].Trim(); } } } } public string AlbumInterpret { get { string ret = ""; foreach (string s in AlbumInterprets) { ret += s + "; "; } if (ret == "") { return unknown; } ret = ret.Substring(0, ret.Length - 2); return ret; } set { if (value == unknown) { AlbumInterprets = new string[0]; } else { string[] split = value.Split(';'); AlbumInterprets = new string[split.Length]; for (int i = 0; i < split.Length; i++) { AlbumInterprets[i] = split[i].Trim(); } } } } public string Composer { get { string ret = ""; foreach (string s in Composers) { ret += s + "; "; } if (ret == "") { return unknown; } ret = ret.Substring(0, ret.Length - 2); return ret; } set { if (value == unknown) { Composers = new string[0]; } else { string[] split = value.Split(';'); Composers = new string[split.Length]; for (int i = 0; i < split.Length; i++) { Composers[i] = split[i].Trim(); } } } } private MP3FileID3v2(string filename, TimeSpan duration) : base(filename) { this.duration = duration; } public override void Save() { File file = File.Create(Filename); file.Tag.Album = Album; file.Tag.AlbumArtists = AlbumInterprets; file.Tag.Composers = Composers; file.Tag.Genres = Genres; file.Tag.Year = ReleaseYear; file.Tag.Title = Titel; file.Tag.Performers = TitelInterpret; file.Tag.Disc = Disc; file.Tag.Track = TitelNum; file.Tag.Copyright = Copyright; IPicture[] pics = new IPicture[Pictures.Length]; for (int i = 0; i < Pictures.Length; i++) { pics[i] = new Picture(Pictures[i]); } file.Tag.Pictures = pics; file.Save(); } public static MP3FileID3v2 Read(string filename) { FileInfo info = new FileInfo(filename); if (info.Exists) { File file = File.Create(filename); MP3FileID3v2 mp3 = new MP3FileID3v2(filename, file.Properties.Duration); mp3.Album = file.Tag.Album; mp3.AlbumInterprets = file.Tag.AlbumArtists; mp3.Composers = file.Tag.Composers; mp3.Genres = file.Tag.Genres; mp3.ReleaseYear = file.Tag.Year; mp3.Titel = file.Tag.Title; mp3.TitelInterpret = file.Tag.Performers; mp3.Disc = file.Tag.Disc; mp3.TitelNum = file.Tag.Track; mp3.Copyright = file.Tag.Copyright; mp3.Pictures = new byte[file.Tag.Pictures.Length][]; for (int i = 0; i < mp3.Pictures.Length; i++) { mp3.Pictures[i] = file.Tag.Pictures[i].Data.ToArray(); } return mp3; } else { throw new ArgumentException("Datei existiert nicht!"); } } public static IEnumerable<MP3FileID3v2> GetAllMP3Files(string directory) { if (System.IO.Directory.Exists(directory)) { var files = System.IO.Directory.GetFiles(directory, "*.mp3", System.IO.SearchOption.AllDirectories); foreach (var file in files) { yield return Read(file); } } } } }

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms; using System.IO; namespace mp3tagedit { public partial class Mp3tagedit : Form { public string filename { get; set; } public Mp3tagedit() { InitializeComponent(); var names = Enum.GetNames(typeof(Genre)).ToList(); names.Sort(); CmbGenre.Items.AddRange(names.ToArray()); } private void BtnOpenFile_Click(object sender, EventArgs e) { CmbGenre.Text = ""; OpenFileDialog openFileDialog = new OpenFileDialog(); openFileDialog.Filter = "MP3|*.mp3"; openFileDialog.Title = "MP3 Datei auswählen"; if (openFileDialog.ShowDialog() == DialogResult.OK) { filename = openFileDialog.FileName; Refresh(filename); } } private void BtnSave_Click(object sender, EventArgs e) { var tag = Encoding.Default.GetBytes("TAG").ToList(); tag.AddRange(FillBytes(Encoding.Default.GetBytes(TxtTitle.Text).ToList(), 30)); tag.AddRange(FillBytes(Encoding.Default.GetBytes(TxtInterpret.Text).ToList(), 30)); tag.AddRange(FillBytes(Encoding.Default.GetBytes(TxtAlbum.Text).ToList(), 30)); tag.AddRange(FillBytes(Encoding.Default.GetBytes(TxtYear.Text).ToList(), 4)); tag.AddRange(FillBytes(Encoding.Default.GetBytes(TxtComments.Text).ToList(), 30)); if (!string.IsNullOrEmpty(CmbGenre.Text)) { Genre genre = (Genre)Enum.Parse(typeof(Genre), CmbGenre.Text.Replace(" ", "_")); tag.Add((byte)genre); } else { tag.Add((byte)Genre.UNKNOWN); } BinaryWriter binaryWriter = new BinaryWriter(File.Open(filename, FileMode.Open)); var id3tag = tag.ToArray(); binaryWriter.BaseStream.Position = binaryWriter.BaseStream.Length - 128; binaryWriter.BaseStream.Write(id3tag, 0, id3tag.Length); binaryWriter.Close(); Refresh(filename); } private void Refresh(string filename) { CmbGenre.Text = ""; BinaryReader binaryReader = new BinaryReader(File.Open(filename,FileMode.Open)); binaryReader.BaseStream.Position = binaryReader.BaseStream.Length - 128; var data = Encoding.Default.GetChars(binaryReader.ReadBytes(128)).ToList(); binaryReader.Close(); string tag = string.Empty; for (int i = 0; i < 3; i++) { tag += data[i]; } if (tag != "TAG") { throw new Exception(); } data.RemoveRange(0, 3); TxtTitle.Text = Read(ref data, 30); TxtInterpret.Text = Read(ref data, 30); TxtAlbum.Text = Read(ref data, 30); TxtYear.Text = Read(ref data, 4); TxtComments.Text = Read(ref data, 30); Genre genre = (Genre)Enum.Parse(typeof(Genre), Enum.GetName( typeof(Genre), Convert.ToByte( Convert.ToChar(Read(ref data, 1)) ) ) ); CmbGenre.SelectedText = genre.ToString().Replace("_", " "); } private List<byte> FillBytes(List<byte> data, int range) { while (data.Count < range) { data.Add(0); } return data; } private string Read(ref List<char> data, int range) { var text = string.Empty; for (int i = 0; i < range; i++) { text += data[i]; } data.RemoveRange(0, range); return text; } private void BtnQuit_Click(object sender, EventArgs e) { this.Close(); } } }