【问题标题】:How to get the lyrics of a song from the song file如何从歌曲文件中获取歌曲的歌词
【发布时间】:2012-06-15 12:54:46
【问题描述】:

iTunes从歌曲文件中获取歌词信息,我想问一下是否有一些方法或API可以从歌曲文件中获取歌词(不使用网络!),在cocoa或carbon中。非常感谢。 :)

【问题讨论】:

  • 我建议使用第三方库,如 TagLib,它知道如何解析各种不同的音乐文件标记标准(ID3v2 用于 MP2/MP3,ITMF 用于 AAC/M4A 等)。如果这看起来是您想要做的,请告诉我,我可以编写一些示例代码。
  • 浏览了不同的API,AudioFileGetProperty(kAudioFilePropertyInfoDictionary) 不包含歌词,kAudioFilePropertyInfoDictionary(kAudioFilePropertyID3Tag) 仅适用于ID3,您仍然需要解析ID3标签,QuickTime不做歌词……我什么也找不到。因此,它必须是第三方库。除非你知道这首歌在 iTunes 曲库中,并且想向 iTunes 索要歌词(当然,这保证给你 iTunes 看到的完全一样的东西)。
  • 附带说明,如果您想在此处使用时间信息(我认为您不会这样做,但未来的搜索者可能会),它是您必须使用的准标准格式解析自己。 ID3v2 确实有一个包含时间信息的“同步歌词”标签,但 iTunes 不会显示。

标签: macos cocoa itunes


【解决方案1】:

而且没有简单的方法可以做到这一点。

您需要使用第三方库。而且,虽然有一些第三方库可以透明地处理读取各种不同格式的标签,但它们只能以这种方式处理“基本集”标签;对于其他任何事情,您必须真正了解这些格式。

例如,使用TagLib,要获取艺术家,您只需这样做:

TagLib::FileRef f1("myfile.mp3");
cout << f1.tag()->artist();
TagLib::FileRef f2("myotherfile.aac");
cout << f2.tag()->artist();

但对于歌词,它是这样的:

TagLib::MPEG::File f1("myfile.mp3");
TagLib::ID3v2::FrameList frames = f1.ID3v2Tag()->frameListMap()["USLT"];
if (!frames.isEmpty()) {
  TagLib::ID3v2::UnsynchronizedLyricsFrame *frame = 
    dynamic_cast<TagLib::ID3v2::UnsynchronizedLyricsFrame *>(frames.front());
  // There could be multiple frames here; you may want to look at language
  // and/or description, instead of just picking the first.
  if (frame) cout << frames->text;
}
TagLib::MP4::File f2("myotherfile.aac");
TagLib::MP4::Item item = f2.tag()->itemListMap()["\xa9lyr"];
TagLib::StringList strings = item.toStringList();
if (!strings.isEmpty()) {
  // As above, there could be multiple strings.
  cout << strings->front();
}

这不是我的想法,所以不要指望它会完全按原样工作。当然,几乎没有错误处理。但是缺少的重要一点是它没有告诉您如何确定您正在处理的文件类型,以及您将从中得到什么类型的标签。 (对于上面的两个示例,这很容易,但是名为“.flac”的文件可以是 OGG FLAC 或原始 FLAC,并且可以具有 VORBISCOMMENT、MetaFLAC、ID3 或 APE 标签。)TagLib 有一些帮助也是,但它仍然不是微不足道的。

幸运的是,如果您只关心获得与 iTunes 10.6.3 完全相同的歌词,那并不难;规则似乎是这样的:

  • 如果扩展名是 MP2 或 MP3(不区分大小写),并且是带有 ID3v2.3 或 ID3v2.4 元数据的 MPEG 音频文件,则第一个 USLT 标签的内容(无论描述或语言)是歌词。
  • 如果扩展名与 .m4?、.aac、.mp4 或其他一些文件匹配,并且它是一个 MPEG-4 文件,其音轨包含 IMTF 元数据,则第一个 ©lyr 块中的第一个字符串的内容是歌词。
  • 在任何其他情况下,都没有歌词。

而且,由于您只处理 ID3v2 和 ITMF,因此为每个使用单独的库实际上可能更简单 - 例如,libmp4v2 处理 MPEG4 文件比 TagLib 更简单(因为它不处理任何东西 但是 MPEG4 文件),类似这样:

MP4FileHandle f = MP4Open("myotherfile.aac");
const MP4Tags *tags = MP4TagsAlloc();
MP4TagsFetch(tags, f);
cout << tags->lyrics;
MP4TagsFree(tags);
MP4Close(f);

此外,如果不必使用本机代码(Cocoa 或 Carbon),则可以使用其他语言的一些更简单的库。例如,在 Python 中,使用Mutagen,您可以这样做:

def printlyrics(path):
  f = mutagen.File(path)
  for key in f.keys():
    if key.startswith('USLT') or key == u'\xa9lyr':
      print f[key]
      return
printlyrics("myfile.mp3")
printlyrics("myotherfile.aac")

当然,我仍然必须知道 ID3v2 将歌词称为“USLT:my desc:'eng'”,而 ITMF 将它们称为“©lyr”,但由于 Python 的动态特性,Mutagen 可以隐藏所有其他细节.

【讨论】:

  • 仅供参考,您不能这样做:TagLib::FileRef f2("myotherfile.aac"); cout &lt;&lt; f2.tag()-&gt;artist(); "aac" 不是 FileRef 的受支持扩展,因此 tag() 将返回 NULL,这将出现段错误。
  • 实际上 taglib 不支持“.aac”文件(它们的设计不支持(参见mail.kde.org/pipermail/taglib-devel/2013-August/002519.html))。运行此答案中的任何 taglib 示例都会导致段错误。
【解决方案2】:

没有简单的方法? 使用 ScriptingBridge 怎么样?问题被标记为“osx”,因此可以假定 iTunes 呈现和使用。如果由于某种原因你不能向 iTunes 询问这些数据,这当然是行不通的

sdef /Applications/iTunes.app | sdp -fh --basename iTunes 获取 iTunes.h

当前的 iTunes 歌曲。

iTunes = [SBApplication applicationWithBundleIdentifier:@"com.apple.iTunes"];
iTunesTrack * currentTrack=[iTunes currentTrack];
NSString * lyrics=[currentTrack lyrics];

请参阅通用 ScriptingBridge 指南中的 https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ScriptingBridgeConcepts/UsingScriptingBridge/UsingScriptingBridge.html#//apple_ref/doc/uid/TP40006104-CH4-SW15

如果你可以的话,你可以遍历所有音乐等

【讨论】:

  • 他有一个歌曲文件,而不是 iTunes 曲目。如果歌曲不在当前的 iTunes 资料库中,这是不可能的。而且,即使它,你也需要通过路径名找到轨道,这需要通过 AE 接口(非常慢)、XML 文件或新的iTunesLibrary 框架来迭代所有轨道找到它,因为搜索位置不起作用。
猜你喜欢
  • 1970-01-01
  • 2020-12-05
  • 2021-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-14
相关资源
最近更新 更多