Go Back   Winamp Forums > Developer Center > Winamp Development

Reply
Thread Tools Search this Thread Display Modes
Old 4th May 2002, 00:32   #1
imotic
Junior Member
 
Join Date: May 2002
Location: a lucid dream
Posts: 17
Send a message via AIM to imotic
event handling

I want to write a program that will execute at the beginning of every song. The program is largely seperate from WinAmp, but I suppose it could be run from within winamp (if I could obtain the same effect).

However, from the programs I've seen, there doesn't seem to be an events framework; you just specify the interval that a loop occurs and that's it. I'd certainly prefer to only execute this program when necessary.

It seems from the developer documentation that Windows Messages largely helps other programs control WinAmp, but I want to do the opposite; I want WinAmp to control this program (by having it execute at every song). Is this possible?

The plan is to upload a file to a server every time the song changes... I can do this from commandline, so everything could work in the background. (I don't need to program sockets or anything, I just need to call a program or a batch file.)

Thanks all..
imotic is offline   Reply With Quote
Old 4th May 2002, 05:08   #2
Jay
Moderator Alumni
 
Jay's Avatar
 
Join Date: May 2000
Location: Next Door
Posts: 8,888
Try just setting up a Windows Timer that is a fairly simple solution and doesn't hurt performance.
Jay is offline   Reply With Quote
Old 4th May 2002, 19:04   #3
imotic
Junior Member
 
Join Date: May 2002
Location: a lucid dream
Posts: 17
Send a message via AIM to imotic
if you mean windows scheduler, the smallest increment there is one day. (at least it is in xp, can't remember about prev. versions.) That's not enough.
imotic is offline   Reply With Quote
Old 4th May 2002, 21:04   #4
Gourou
Senior Member
 
Gourou's Avatar
 
Join Date: Feb 2002
Location: The backside of the universe on the trailing edge of eternity
Posts: 238
*smacks his head* no, not quite what he meant when they talked about a timer, he meant a timer you create from inside of a program. First off, what language do you plan on using? C++, C, C#, Delphi, VB, that's the first thing, second, since a plug is harder to do than a program external, does it have to be a plugin, or would a simple program you run work? a program that only checks a timer once a second is going to take next to 0 CPU, meaning it'll hit less than 1% every second to check the timer, so you wont even notice it's running.
Gourou is offline   Reply With Quote
Old 4th May 2002, 21:10   #5
imotic
Junior Member
 
Join Date: May 2002
Location: a lucid dream
Posts: 17
Send a message via AIM to imotic
any language is fine. I've never written a plug-in, and I've never written a windows service, hell I just downloaded the MS SDK yesterday... but I've got a free summer and I'm up for learning new things.

I've thought about polling... which I don't mind. I just wanted to check if there were any events triggers, which I would prefer. If there aren't, then I'll just go with a polling solution.
imotic is offline   Reply With Quote
Old 4th May 2002, 21:41   #6
Gourou
Senior Member
 
Gourou's Avatar
 
Join Date: Feb 2002
Location: The backside of the universe on the trailing edge of eternity
Posts: 238
yes, I do believe in winamp 2.x that polling is the only solution, if I remember correctly, winamp 3.x supports call-backs, but I could be very wrong, and it would only work for a plugin. C++ will give you the smallest cpu and memory footprint, and it will be how you would do a dll, but I am a vbenite, and I could whip together that pretty quickly, just a couple minutes, so it's up to you, if your just starting out, and have the ambition, I would honestly say start in c/c++ and learn from the ground up, you'll need to check out the forums here for how to grab the song title, it is by no means a simple 2 sendmessage() commands, so try to remember that as the summer progresses.
Gourou is offline   Reply With Quote
Old 4th May 2002, 21:47   #7
imotic
Junior Member
 
Join Date: May 2002
Location: a lucid dream
Posts: 17
Send a message via AIM to imotic
well I've got gen_titlespy installed, which kicks out the song name to a text file. The plan now is to poll every second or so and see if the contents of the text file have changed. If so, I want to execute a program with certain arguments.

I'm thinking that writing a service would be the best way to go? Or is there a different framework that I should look into?

Thanks all for the advice thus far.
imotic is offline   Reply With Quote
Old 4th May 2002, 22:05   #8
Gourou
Senior Member
 
Gourou's Avatar
 
Join Date: Feb 2002
Location: The backside of the universe on the trailing edge of eternity
Posts: 238
polling the file will be 'relatively' far more intensive than polling winamp itself, considering your going to be making a file hit every second, versus a memory hit, but the choice is yours, also, if you were to check winamp yourself, you could output the file, and get rid of the gen plugin altogether... as far as a service goes, I dont think it much matters, you can hide your program completely normally, so I guess it's just up to you, depends on how much you wish to learn in the process.
Gourou is offline   Reply With Quote
Old 5th May 2002, 00:36   #9
lldecker
Junior Member
 
Join Date: May 2002
Posts: 3
polling?

what exactly do you mean by polling? i came on to this forum at the right time because i needed help with the exact same issue

im using a dll (that has no relation to a plugin or anything) to call API functions to manipulate winamp. (its a dll for a game and im adding support for winamp).

i know how to get the song title, im just having trouble figuring out how to do the 'event' deal.

right now ive got it set up like this (ignore the cvar struct and most of the 'if's :

void Winamp::getTitle()
{
if(mytime == ClientTime::current) //song is over (750ms into next song, actually)
{
char this_title[2048],*p; //to hold actual title, size
GetWindowText(hwnd,this_title,sizeof(this_title)); //get title from winamp

//trim winamp from title (borrowed from nullsoft :
p = this_title+strlen(this_title)-8;
while (p >= this_title)
{
if (!strnicmp(p,"- Winamp",8)) break;
p--;
}

if (p >= this_title) p--;
while (p >= this_title && *p == ' ') p--;
*++p=0;

Con_Echo("Current song: %s", this_title);

getNTime(); //get time left of new song

}
else { getTitle(); } //song isnt over, so check again

}


void Winamp::getNTime()
{
if((playing)&&(cvar.wa_name>0))
{
//mytime = (total track length - current position position) + 750 + Current time
//which is time left + 750 (750ms into the next song)
//all in ms
mytime = (((SendMessage(hwnd,WM_USER,1,105)*1000)-SendMessage(hwnd,WM_USER,0,105))+750)+ClientTime::current;
getTitle(); //start the new loop
}
}

NOTES:

-ClientTime::current returns the current system time in ms (ticks?)
-Con_Echo(); outputs text to the screen (defined in a different file)
-To start the loop just call getNTime(); (the playing bool designates if a file is actually playing, and cvar.wa_name designates if the user even wants to see the titles).
-For example, i would use API to start playing, then just call getNTime();
-getNTime would set the mytime var as '750ms into the next song' and then call getTitle
-(now in getTitle), if current system time is mytime (if we are 750ms into the next song), that means that the new song has started, so fetch the filename and call getNTime() to reset the mytime var and start the loop again
-if current system time is NOT mytime (if we are still playing the same song), getTitle() calls itself (making a loop), and will not stop calling itself until current system time == mytime (we are 750ms into the next song).

this compiles fine, but when i run it, i get a stack overflow. i assume its because either c++ or my computer (or the nature of computers themselves) cant handle that loop. is there a way that i would be able to get the time left in the current file, and then just delay the next command (which would be to display the file name) for x milliseconds (x being time left)? i know of a c++ delay command, but i believe that that will actually halt the whole dll (similar to SLEEP for QBASIC). i just want to delay that one command.

any help? thanks
lldecker is offline   Reply With Quote
Old 5th May 2002, 04:32   #10
Jay
Moderator Alumni
 
Jay's Avatar
 
Join Date: May 2000
Location: Next Door
Posts: 8,888
that's a bad idea because the user could manually change the currently playing song and therefore you program would lose its accuracy. It is just best and easiest to set up a windows timer that checks the title ever x seconds, when the title changes do your action.
Jay is offline   Reply With Quote
Old 5th May 2002, 04:55   #11
lldecker
Junior Member
 
Join Date: May 2002
Posts: 3
well

i looked ahead about that. when the user pauses or stops the current song, the loop stops (because playing=0), and when a user goes to the next song it stops the loop and calls getNTime() again, getting a new time. it would work.

i like the idea of using a timer, but what my previous post was asking was how do i implement windows timers with c++?

thanks
lldecker is offline   Reply With Quote
Old 5th May 2002, 06:07   #12
Jay
Moderator Alumni
 
Jay's Avatar
 
Join Date: May 2000
Location: Next Door
Posts: 8,888
Well in VC++ you can use SetTimer() and KillTimer()

I believe they are API calls not MFC, but I could be wrong.
Jay is offline   Reply With Quote
Old 5th May 2002, 21:56   #13
install
Junior Member
 
Join Date: May 2002
Posts: 6
It's obvious why you get a stack overflow.

void Winamp::getNTime()
{
...
mytime = (((SendMessage(hwnd,WM_USER,1,105)*1000)-SendMessage(hwnd,WM_USER,0,105))+750)+ClientTime::current;
// so here you set mytime to point 750 seconds into the next song
// please note that mytime is definetly not equal to
// ClientTime::current at this point. (e.g. because you added 750)
// then you do:
getTitle();
}

void Winamp::getTitle()
{
if(mytime == ClientTime::current)
// what's this compare? you're comparing milliseconds with == ???
// would be a real coincidence if your ClientTime::current equals
// mytime (or are you polling each 100 microseconds??) should be ">"
// I guess, not "=="
// anyway from your call above mytime is definetly not clienttime::current
// so the else statement gets executed, the function calls itself
// and again the else statement is executed (as neither mytime nor clienttime changed)
// and again and again, until the stack overflows...
{
... some code to handle track changes
}
else { getTitle(); } //song isnt over, so check again


BTW you can also create a low priority polling thread (with CreateThread(), SetThreadPriority(), and Sleep()). That's what I prefer, as SendMessage can takes ages to complete, as it has to wait for Winamp to answer.

Last edited by install; 5th May 2002 at 22:17.
install is offline   Reply With Quote
Old 5th May 2002, 22:36   #14
lldecker
Junior Member
 
Join Date: May 2002
Posts: 3
i think i kind of fixed it up. i am now using a completely different method:

void Winamp::getTitle()
{
Con_Echo("into getTitle()");
if((playing)&&(cvar.wa_name>0)&&(!stop))
{
char this_title[2048],*p; //to hold actual title, size
GetWindowText(hwnd,this_title,sizeof(this_title)); //get title from winamp

//trim winamp from title (borrowed from nullsoft :
p = this_title+strlen(this_title)-8;
while (p >= this_title)
{
if (!strnicmp(p,"- Winamp",8)) break;
p--;
}

if (p >= this_title) p--;
while (p >= this_title && *p == ' ') p--;
*++p=0;

Con_Echo("Current song: %s", this_title);
titleLoop(); //it was a new song, so call titleLoop() to grab the new song's length
//and restart the loop.
}
}

void Winamp::Wait()
{
Con_Echo("into Wait");
if((playing)&&(cvar.wa_name>0)&&(!stop))
{
//keep checking until "current song time!=songtime" - its a new song
while(SendMessage(hwnd,WM_USER,1,105)==songtime) { }
getTitle();
}
}

void Winamp::titleLoop()
{
Con_Echo("into titleLoop");
if((playing)&&(cvar.wa_name>0)&&(!stop))
{
songtime=SendMessage(hwnd,WM_USER,1,105); //how long is the current song?
Con_Echo("songtime: %s",songtime);
Wait(); //go into the loop
}
}

i now no longer use a recursive function (which is what was causing the stack overflow). now when i start the loop (with titleLoop), it establishes how long the current song is, and then keep checking if the song time has changed (a new song started) with Wait(). if it has, it fetches the title, outputs it, and restarts the whole thing.

however, this still doesnt work, as my program crashes with:
"The command at [hex] referenced memory at [hex]. The memory could not be 'read'"

i would do polling with a separate thread, but i have no idea how. could anyone start me off in that direction with some code?

thanks
lldecker is offline   Reply With Quote
Old 6th May 2002, 10:19   #15
install
Junior Member
 
Join Date: May 2002
Posts: 6
Quote:
while(SendMessage(hwnd,WM_USER,1,105)==songtime) { }
That will make your app hang badly when winamp is not playing, or paused. BTW that nice nullsoft title getting code ignores the return value of GetWindowText(), so you could crash if GetWindowText fails (returns 0).

msdn has examples for CreateThread(). I'm not going to write the code for you, but your new thread has to do a loop where it does something like:

{
Sleep(5 seconds);
Query Winamp Title+time;
Store it into a variable(s) accesible by the main thread;
repeat that stuff;
}

You might want to synchronize access to that variable(s) between the two threads with a Mutex or Critical Section. Welcome to the world of thread programming...

Of course you can also just call SendMessage() if you don't mind that your app hangs until Winamp answers. BTW if you just want to send commands that dont depend on return value like e.g. "play", I would suggest you use PostMessage() instead of SendMessage().
install is offline   Reply With Quote
Old 9th October 2002, 03:08   #16
oopsitzice
Junior Member
 
Join Date: Aug 2002
Posts: 8
how would u just do play, stop, pause, next song, previous song, and volume, for DLL? thats all i wanna know dont care for song title.
oopsitzice is offline   Reply With Quote
Old 15th October 2002, 01:29   #17
KleptomaN
Junior Member
 
Join Date: Sep 2002
Posts: 8
Send a message via ICQ to KleptomaN
There are 2 Windows API functions that enable you to process any message sent to any window in addition or instead of the normal way the window does this...

GetWindowLong, SetWindowLong and CallWindowProc are their names.

GetWindowLong(hwnd, GWL_WNDPROC) returns a pointer to the window procedure of the Window whose handle is hwnd (this is the procedure that handles messages for this window)

SetWindowLong (hwnd, GWL_WNDPROC, NewWindowProc) sets the window procedure to the procedure that NewWindowProc points to.

NewWindowPointer is an integer that has to point to a procedure of yours, with no return value (void) that has 1 paramater whose type is a Windows Message (the fields are Msg, Wparam, Lparam, Result).

After calling SetWindowProc, every single message (activation, mouse clicks, keystrokes, window paint, EVERYTHING) goes to your procedure instead of the original window's procedure.

But you'll have to call the original window procedure at some point during the run of your function. This is done like this:

mess.Result <- CallWindowProc(DefaultWindowProc, hwnd, mess.Msg, mess.wParam, mess.lParam)

Assume that "hwnd" is the handle to the window, "mess" is the paramater of your function (the message sent to the window), and "DefaultWindowProc" is an integer that points to the original window procedure (returned by the call to GetWindowLong)

I've posted a more detailed explanation and an example on how to use this trick in this thread.
KleptomaN is offline   Reply With Quote
Old 23rd April 2003, 22:21   #18
smorks
Junior Member
 
Join Date: Apr 2003
Posts: 1
is there a list of events that is possible to receive using the above technique somewhere? i've searched through the forums and looked through the sdk stuff, and can't seem to find anything about that...
smorks is offline   Reply With Quote
Reply
Go Back   Winamp Forums > Developer Center > Winamp Development

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump