Читать APEv2 mp3 тег с TagLibSharp?
СЦЕНАРИЙ
Я обычно использую приложение MP3Gain, чтобы установить усиление воспроизведения mp3-файлов.
Приложение может создать следующие поля в теге APEv2 mp3-файлов:
(скриншот взят из плеера WinAmp)
ВОПРОС
С библиотекой TagLibSharp я написал парсер ID3v1 и ID3v2, теперь мне интересно, смогу ли я читать и писать упомянутые поля APEv2, используя эту библиотеку?.
ИССЛЕДОВАНИЕ
Я думаю, что приложение MP3Gain использует уникальные имена для полей, поэтому, вероятно, TagLibsharp не поддерживает их, однако библиотека TagLibsharp имеет ReadBlock()
, Removeblock()
, Find()
а также RFind()
методы, для которых я думаю, это то, что мне нужно использовать, но я не знаю точно, как использовать их в сочетании...
Это единственное, что у меня есть:
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)
И это псевдокод, написанный на Vb.Net только для демонстрации ожидаемой абстракции или поведения.
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
ОБНОВИТЬ:
Я думаю, что я, наконец, закончил часть "Чтение", однако я не уверен, как записать блоки, потому что, если поле не существует, я могу перезаписать / повредить файл...
''' ----------------------------------------------------------------------------------------------------
''' <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
1 ответ
Процесс получения APEv2-специфичной информации из файла TagLib# аналогичен процессу для тега ID3v2, описанному в этом ответе.
Вот как прочитать значение:
// 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());
}
}
Я не уверен из скриншота, является ли поле одной строкой или двумя показанными строками, соединенными запятой.
Сохранение будет в обратном направлении, но немного проще:
// 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();
Пример для Vb.Net:
Поля:
ReadOnly mp3File As Global.TagLib.Mpeg.AudioFile = ...
Свойства (связанные с MP3Gain):
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 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
Метод "Установить":
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