PDA

View Full Version : Reading ID3 tags from file playing in Winamp


NeM2k3
14th December 2003, 18:07
I'm using the code unearthed in here (http://forums.winamp.com/showthread.php?s=&threadid=85389&highlight=Solution+Get+FileName+from+external+app%2Fdll) to get the path to the currently playing file in Winamp, then using some Delphi code to read the ID3 tag information:


type
TID3Rec = packed record
Tag : array[0..2] of Char;
Title,
Artist,
Comment,
Album : array[0..29] of Char;
Year : array[0..3] of Char;
Genre : Byte;
end;

...

fmp3:=TFileStream.Create(tempStr, fmOpenRead);
try
fmp3.position:=fmp3.size-128;
fmp3.Read(ID3,SizeOf(ID3));
finally
fmp3.free;
end;


This works fine when the MP3 is paused or not open in Winamp, but when Winamp is playing the file I get errors along the lines of "Cannot open file for read access". Someone else I've been talking to has written something similar in C++ and he uses


fopen(fname, "r");


to do the same thing and it works like a charm for him.

Why does it work for him in C++ and not for me in Delphi?? It's really bugging me :)

Maxim
15th December 2003, 09:52
Delphi has a fair few different ways of opening files, some of which allow you to open a file with read-only shared access and some which don't. Try changing the last parameter in the TFileStream.Create() to whatever the shard option is (something like fmOpenReadShared, F1 is your friend).

However, if your program will always be running at the same time as Winamp (and possibly when it isn't if you link directly to in_mp3.dll, which is a bit dodgy and harder) I would recommend you make use of the new(ish) winampGetExtendedFileInfo() calls/messages, which allow you to query tag fields in all (supported) formats using in_mp3's code, so you get automatic support for a lot more cool stuff like id3v2.

Maxim

NeM2k3
15th December 2003, 22:34
I had already tried all those other file modes and none of them worked either. I ended up using lower-level file I/O routines.

Where can I find out about this winampGetExtendedFileInfo() function? I haven't heard of that one before (tried searching the forums and it doesn't seem to be in the API).

Maxim
16th December 2003, 14:58
In the 2.90 SDK:

#define IPC_SET_EXTENDED_FILE_INFO 294 //pass a pointer to the a extendedFileInfoStruct in wParam
/* (requires Winamp 2.9+)
** to use, create an extendedFileInfoStruct, point the values filename and metadata to the
** filename and metadata field you wish to write in ret. (retlen is not used). and then
** SendMessage(hwnd_winamp,WM_WA_IPC,&struct,IPC_SET_EXTENDED_FILE_INFO);
** returns 1 if the metadata is supported
** Call IPC_WRITE_EXTENDED_FILE_INFO once you're done setting all the metadata you want to update
*/

There's a lot of pointer usage there, which is a hassle in Delphi if you're not used to it. This code is entirely untested and off the top of my head:


function GetArtist:string;
const
IPC_GET_EXTENDED_FILE_INFO=294;
var
ExFileInfoSt: record
fn,meta,ret:PChar;
retlen:integer;
end;
Value:array[0..255] of Char;
that
begin
ExFileInfoSt.fn=PChar("c:\file.mp3");
ExFileInfoSt.meta=PChar("artist"); // various values available, experiment
ExFileInfoSt.ret=Value;
ExFileInfoSt.retlen=255;
SendMessage(hwnd_winamp,WM_WA_IPC,@ExFileInfoSt,IPC_GET_EXTENDED_FILE_INFO);
result=Value;
end;

This is assuming you're in-process to be able to pass the pointers. If not... it's harder. You can link directly to in_mp3.dll which contains the function that services this message, although you shouldn't really do that I suppose (and it reduces your support to only those formats in_mp3 supports). Or, you can use some of the tricks for stealing memory from Winamp's buffers to use yourself - the minibrowser URL's a good one to steal, since it's 4KB. See here (http://forums.winamp.com/showthread.php?postid=1179901#post1179901) for some details on doing that.

Maxim

michou
8th June 2005, 19:15
I it's gonna sound sound kinda idiot, but I can't get my code to work with IPC_GET_EXTENDED_FILE_INFO in C++ (DevC++)

with something like:

char buffer[512] = {0};
extendedFileInfoStruct object;
UINT plpos = SendMessage(plugin.hwndParent, WM_WA_IPC, 0, IPC_GETLISTPOS);
char *faka = (char*)SendMessage(plugin.hwndParent, WM_WA_IPC, plpos, IPC_GETPLAYLISTFILE);
object.filename= faka;
object.metadata = "Artist";
object.ret = buffer;
object.retlen = 512;

I get *always* empty fields... :(
And by the way, what are the possible values for the metadata field of a extendedFileInfoStruct ?