Reputation: 20464
I normally use the MP3Gain application to set the replay gain of mp3 files.
The application can create these fields in the APEv2 tag of mp3 files:
(screenshot is taken from WinAmp player)
With TagLibSharp library I wrote a ID3v1 and ID3v2 parser, now, I wonder if I could read and write the mentioned APEv2 fields using this library?.
I think that MP3Gain app uses unique names for the fields so probably TagLibsharp does not supports them, however, TagLibsharp library has a ReadBlock()
, Removeblock()
, Find()
and RFind()
methods for which I think is what I need to use, but I don't know exactly how to use them in conjunction...
This is the only what I have:
Dim file As New TagLib.Mpeg.AudioFile("C:\input.mp3")
Dim data As Byte() = Encoding.ASCII.GetBytes("MP3GAIN_MINMAX")
Dim vector As New ByteVector(data)
Dim offset As Long = file.Find(vector)
And this is a pseudo-code written in Vb.Net just to demostrate the expected abstraction or behavior.
Imports TagLib
Public NotInheritable Class Mp3File
Private tagFile As Global.TagLib.Mpeg.AudioFile
Public ReadOnly Property APEv2 As APEv2Tag
Get
Return Me.apeTagB
End Get
End Property
Private ReadOnly apeTagB As APEv2Tag
Public Sub New(ByVal file As FileInfo)
Me.tagFile = New Global.TagLib.Mpeg.AudioFile(file.FullName)
Me.apeTagB = New APEv2Tag(Me.tagFile)
End Sub
End Class
''' <summary>
''' Represents the APEv2 tag for a MP3 file.
''' </summary>
Public Class APEv2Tag
Protected ReadOnly mp3File As Global.TagLib.Mpeg.AudioFile
Public Sub New(ByVal mp3File As Global.TagLib.Mpeg.AudioFile)
Me.mp3File = mp3File
End Sub
Public Overridable Property MP3GAIN_MINMAX As Double
Get
If field exists then...
Return TheValue...
End If
End Get
Set(ByVal value As Double)
...
End Set
End Property
' More properties here...
End Class
I think that I finally finished by myself the "Read" part, however I'm not sure how to write the blocks because if the field does not exists surelly I could overwritte/corrupt the file...
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Gets the <c>MP3GAIN_MINMAX</c> metatada field of the audio file.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <returns>
''' The <c>MP3GAIN_MINMAX</c> field value.
''' </returns>
''' ----------------------------------------------------------------------------------------------------
<DebuggerStepThrough>
Private Function GetFieldMP3GainMinMax() As String
Dim data As Byte() = Encoding.UTF8.GetBytes("MP3GAIN_MINMAX")
Dim vector As New ByteVector(data)
Dim offset As Long = Me.mp3File.Find(vector)
Dim result As String
If (offset = -1) Then
Return String.Empty
Else
Try
offset += ("MP3GAIN_MINMAX".Length + 1)
Me.mp3File.Seek(offset, SeekOrigin.Begin)
result = Me.mp3File.ReadBlock(8).ToString.TrimEnd()
Return result
Catch ex As Exception
Throw
Finally
Me.mp3File.Seek(0, SeekOrigin.Begin)
End Try
End If
End Function
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Gets the <c>MP3GAIN_UNDO</c> metatada field of the audio file.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <returns>
''' The <c>MP3GAIN_UNDO</c> field value.
''' </returns>
''' ----------------------------------------------------------------------------------------------------
<DebuggerStepThrough>
Private Function GetFieldMP3GainUndo() As String
Dim data As Byte() = Encoding.UTF8.GetBytes("MP3GAIN_UNDO")
Dim vector As New ByteVector(data)
Dim offset As Long = Me.mp3File.Find(vector)
Dim result As String
If (offset = -1) Then
Return String.Empty
Else
Try
offset += ("MP3GAIN_UNDO".Length + 1)
Me.mp3File.Seek(offset, SeekOrigin.Begin)
result = Me.mp3File.ReadBlock(12).ToString.TrimEnd()
Return result
Catch ex As Exception
Throw
Finally
Me.mp3File.Seek(0, SeekOrigin.Begin)
End Try
End If
End Function
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Gets the <c>REPLAYGAIN_TRACK_GAIN</c> metatada field of the audio file.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <returns>
''' The <c>REPLAYGAIN_TRACK_GAIN</c> field value.
''' </returns>
''' ----------------------------------------------------------------------------------------------------
<DebuggerStepThrough>
Private Function GetFieldReplayGainTrackGain() As String
Dim data As Byte() = Encoding.UTF8.GetBytes("REPLAYGAIN_TRACK_GAIN")
Dim vector As New ByteVector(data)
Dim offset As Long = Me.mp3File.Find(vector)
Dim result As String
If (offset = -1) Then
Return String.Empty
Else
Try
offset += ("REPLAYGAIN_TRACK_GAIN".Length + 1)
Me.mp3File.Seek(offset, SeekOrigin.Begin)
result = Me.mp3File.ReadBlock(12).ToString.TrimEnd()
Return result
Catch ex As Exception
Throw
Finally
Me.mp3File.Seek(0, SeekOrigin.Begin)
End Try
End If
End Function
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Gets the <c>REPLAYGAIN_TRACK_PEAK</c> metatada field of the audio file.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <returns>
''' The <c>REPLAYGAIN_TRACK_PEAK</c> field value.
''' </returns>
''' ----------------------------------------------------------------------------------------------------
<DebuggerStepThrough>
Private Function GetFieldReplayGainTrackPeak() As String
Dim data As Byte() = Encoding.UTF8.GetBytes("REPLAYGAIN_TRACK_PEAK")
Dim vector As New ByteVector(data)
Dim offset As Long = Me.mp3File.Find(vector)
Dim result As String
If (offset = -1) Then
Return String.Empty
Else
Try
offset += ("REPLAYGAIN_TRACK_PEAK".Length + 1)
Me.mp3File.Seek(offset, SeekOrigin.Begin)
result = Me.mp3File.ReadBlock(8).ToString.TrimEnd()
Return result
Catch ex As Exception
Throw
Finally
Me.mp3File.Seek(0, SeekOrigin.Begin)
End Try
End If
End Function
Upvotes: 2
Views: 861
Reputation: 27550
The process for getting APEv2 specific information from a TagLib# file is similar to the process for an ID3v2 tag described in this answer.
Here's how to read the value:
// Get the APEv2 tag if it exists.
TagLib.Ape.Tag ape_tag = (TagLib.Ape.Tag)file.GetTag(TagLib.TagTypes.Ape, false);
if(ape_tag != null) {
// Get the item.
TagLib.Ape.Item item = ape_tag.GetItem("MP3GAIN_MINMAX");
if (item != null) {
Console.Log(item.ToStringArray());
}
}
I'm not sure from the screenshot if the field is a single string or two strings shown joined by a comma.
Saving would be the reverse direction but a little simpler:
// Get the APEv2 tag if it exists.
TagLib.Ape.Tag ape_tag = (TagLib.Ape.Tag)file.GetTag(TagLib.TagTypes.Ape, true);
if(ape_tag != null) {
ape_tag.SetValue("MP3GAIN_MINMAX", value);
}
file.Save();
An example, for Vb.Net:
Fields:
ReadOnly mp3File As Global.TagLib.Mpeg.AudioFile = ...
Properties (MP3Gain related):
Property MP3GainMinMax As String
Get
Return Me.GetField("MP3GAIN_MINMAX")
End Get
Set(ByVal value As String)
Me.SetField("MP3GAIN_MINMAX", value)
End Set
End Property
Property MP3GainUndo As String
Get
Return Me.GetField("MP3GAIN_UNDO")
End Get
Set(ByVal value As String)
Me.SetField("MP3GAIN_UNDO", value)
End Set
End Property
Property ReplayGainTrackGain As String
Get
Return Me.GetField("REPLAYGAIN_TRACK_GAIN")
End Get
Set(ByVal value As String)
Me.SetField("REPLAYGAIN_TRACK_GAIN", value)
End Set
End Property
Property ReplayGainTrackPeak As String
Get
Return Me.GetField("REPLAYGAIN_TRACK_PEAK")
End Get
Set(ByVal value As String)
Me.SetField("REPLAYGAIN_TRACK_PEAK", value)
End Set
End Property
Function 'Get':
Function GetField(ByVal fieldName As String) As String
Dim apeTag As TagLib.Ape.Tag =
DirectCast(Me.mp3File.GetTag(TagTypes.Ape, create:=False), TagLib.Ape.Tag)
If (apeTag IsNot Nothing) Then
Dim item As TagLib.Ape.Item = apeTag.GetItem(fieldName)
If (item IsNot Nothing) Then
Return item.ToString()
End If
End If
Return String.Empty
End Function
Method 'Set':
Sub SetField(ByVal fieldName As String, ByVal value As String)
Dim apeTag As TagLib.Ape.Tag =
DirectCast(Me.mp3File.GetTag(TagTypes.Ape, create:=True), TagLib.Ape.Tag)
apeTag.SetValue(fieldName, value)
End Sub
Upvotes: 5