RetVal
RetVal

Reputation: 107

How to get the lyrics of a song from the song file

iTunes get the lyrics information from a song file

iTunes get the lyrics information from a song file, and I want to ask if there are some methods or APIs to get the lyrics from the song file(not use network!),in cocoa or carbon.Thank you very much. :)

Upvotes: 3

Views: 5658

Answers (2)

Tauri
Tauri

Reputation: 1299

no easy way? what about using ScriptingBridge?. Question is tagged 'osx' so iTunes can be assumed to present and used. If you can't for some reason ask iTunes about this data, this won't work of course

sdef /Applications/iTunes.app | sdp -fh --basename iTunes to get iTunes.h

for current iTunes song.

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

see https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ScriptingBridgeConcepts/UsingScriptingBridge/UsingScriptingBridge.html#//apple_ref/doc/uid/TP40006104-CH4-SW15 on general ScriptingBridge guide

you can iterate over all music,etc if that's ok for you

Upvotes: 0

abarnert
abarnert

Reputation: 365587

And there is no easy way to do this.

You will need to use a third-party library. And, while there are some third-party libraries that transparently handle reading tags from a variety of different formats, they only handle the "basic set" of tags that way; for anything else, you have to actually know about the formats.

For example, with TagLib, to get the artist, you just do this:

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

But for lyrics, it's something like this:

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();
}

That's off the top of my head, so don't expect it to work exactly as-is. And of course there's almost no error handling. But the big thing that's missing is that it doesn't show you how to figure out what type of file you're dealing with, and what type of tag you'll get out of it. (This is pretty easy with the two examples above, but a file named ".flac" could be either an OGG FLAC or a raw FLAC, and could have VORBISCOMMENT, MetaFLAC, ID3, or APE tags.) TagLib has stuff to help there as well, but it's still not trivial.

Fortunately, if you only care about getting exactly the same lyrics as iTunes 10.6.3, it's not that hard; the rules seem to be something like this:

  • If the extension is MP2 or MP3 (case-insensitive), and it's an MPEG audio file with ID3v2.3 or ID3v2.4 metadata, the contents of the first USLT tag (no matter what the description or language) are the lyrics.
  • If the extension matches .m4?, .aac, .mp4, or maybe a few others, and it's an MPEG-4 file with an audio track with IMTF metadata, the contents of the first string in the first ©lyr chunk are the lyrics.
  • In any other case, there are no lyrics.

And, since you're only dealing with ID3v2 and ITMF, it may actually be simpler to use separate libraries for each—for example, libmp4v2 handles MPEG4 files more simply than TagLib (because it doesn't handle anything but MPEG4 files), something like this:

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

Also, if this doesn't have to be in native code (Cocoa or Carbon), there are some simpler libraries in other languages. For example, in Python, with Mutagen, you can do this:

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")

Of course I still had to know that ID3v2 calls lyrics "USLT:my desc:'eng'" while ITMF calls them "©lyr", but because of the dynamic nature of Python, Mutagen can hide all of the other details.

Upvotes: 2

Related Questions