Old 6th May 2010, 11:49   #1
rahulthewall
Junior Member
 
Join Date: Apr 2010
Posts: 23
Activating a plugin

So, I am working on this plugin - which implements another shuffle mode for winamp.

Now, I can do some configurations when the plugin is loaded - but this will happen each time winamp starts and the plugin is present in the plugin directory. What I want is that the plugin starts working after the user explicitly states so. So if the user jumps into this smart shuffle mode - the plugin will play a random song from his/her library and then play subsequent songs from there on.

The plugin should do nothing when winamp starts, it should only start functioning when the user wants it to.

How can I go about achieving that?

Thanks a lot for your replies - and also thanks a million times for the prompt replies that I have got for my other requests. Kudos to all.
rahulthewall is offline   Reply With Quote
Old 6th May 2010, 12:18   #2
DrO
 
Join Date: Sep 2003
Posts: 27,873
it all depends on how you want the user to enable the feature as to how you setup things to work. for example you can subclass Winamp and wait for a menu item which you've added) to be checked - this then just requires a subclass in the init(..) function and sits there waiting.

or it can be done via an action from a config dialog called via the config(..) callback in the preferences->plug-in page.

or have a window created on init which then just waits for the user to click on it.

as you see, it all depends on how you want the user to enable such things and what level of integration into the Winamp you're trying to go for (external floating windows don't invoke good integration imho unless done in a skinned embedwnd frame).

-daz
DrO is offline   Reply With Quote
Old 6th May 2010, 12:28   #3
rahulthewall
Junior Member
 
Join Date: Apr 2010
Posts: 23
I would want:

- Menu item (already created) -> however it is selected by default right now.
- Hotkey -> which is the same as someone clicking on the menu option.

Another question - what is the alternative to printf when it comes to debugging a plugin. I am using MessageBox but that is quite cumbersome right now.

On that note, I would like to know what are the types of message boxes that I can use - or where are they defined.

Thanks a lot again.
rahulthewall is offline   Reply With Quote
Old 6th May 2010, 13:28   #4
DrO
 
Join Date: Sep 2003
Posts: 27,873
for the menu i'd make sure to use IPC_GET_HMENU to add it early on (have posted the info from wa_ipc.h which gives an idea of how the api is used for adding to the menus but you can change which menu as required - sometimes you need to use a resource editor to work out the index of the menu especially when getting the main menu resource).
PHP Code:
#define IPC_GET_HMENU 281
/* (requires Winamp 2.9+)
** HMENU hMenu=SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)0,IPC_GET_HMENU);
**
** For 2.9x installs the following values are valid:
** 0 : main popup menu (mapped to -1 in 5.x installs)
** 1 : main menubar file menu
** 2 : main menubar options menu
** 3 : main menubar windows menu
** 4 : main menubar help menu
**
** For 5.x client versions the following values are valid (changed due to Modern skin support):
** -1 : the main winamp menu resource (same as doing LoadMenu(winamp_module_or_lng_file,101)
**  0 : main popup menu 
**  1 : main menubar file menu
**  2 : main menubar play menu
**  3 : main menubar options menu
**  4 : main menubar windows menu
**  5 : main menubar windows help
**  6 : playlist editor menubar file menu
**  7 : playlist editor menubar playlist menu
**  8 : playlist editor menubar sort menu
**  9 : media library menubar file menu
** 10 : media library menubar view menu
**
** In all client versions, unsupported values will return NULL.
**
** e.g. (psuedo code to add an item to the end of the main window 'view' menu)
** HMENU windows_menu = (HMENU)SendMessage(hwnd_winamp,WM_WA_IPC,4,IPC_GET_HMENU);
** if(windows_menu)
** {
**   // WA_MENUITEM_ID is obtained from IPC_REGISTER_WINAMP_IPCMESSAGE or a predefined
**   // value if that api is not supported on the client version you are working with.
**
**   int window_visible = 1; // this would be updated as needed for the window view state
**   MENUITEMINFO i = {sizeof(i), MIIM_ID | MIIM_STATE | MIIM_TYPE, MFT_STRING,
**                     window_visible ? MFS_CHECKED : 0, WA_MENUITEM_ID};
**   i.dwTypeData = "My Menu Item";
**   InsertMenuItem(windows_menu, GetMenuItemCount(windows_menu), TRUE, &i);
** }
*/ 
for the hotkey there's information in wa_hotkeys.h on how to do it (though i can't remember how different it is from the internal version other than missing a #define for something added in the next client release).

as for debgging, OutputDebugString(..) can work (though it doesn't accept printf(..) formatters, just a string buffer. or logging to a file or doing anyother visual indicator - just remember about UI blocking and the effect that can have especially if doing things against the main Winamp thread.

http://msdn.microsoft.com/en-us/libr...8VS.85%29.aspx has everything about the MessageBox(..) api though you can also just create a dialog if the MessageBox doesn't fit with what you need (as that is what it essentially is anyway).
DrO is offline   Reply With Quote
Old 18th May 2010, 14:39   #5
rahulthewall
Junior Member
 
Join Date: Apr 2010
Posts: 23
In case anyone wants to use this information later, I am posting that exact code that worked for me - along with a question that I have.

code:

#define SMART_SHUFFLE_PLAYLIST L"Smart Shuffle Current Playlist"

HMENU windows_menu = (HMENU)SendMessage(plugin.hwndParent,WM_WA_IPC,(WPARAM)2,IPC_GET_HMENU);
if (windows_menu) {
DWORD WA_MENUITEM_ID = 65537;
int window_visible = 1;
MENUITEMINFO i = {sizeof(i), MIIM_ID | MIIM_STATE | MIIM_TYPE, MFT_STRING, window_visible ? MFS_CHECKED : 0, WA_MENUITEM_ID};
i.dwTypeData = SMART_SHUFFLE_LIBRARY;
InsertMenuItem(windows_menu, GetMenuItemCount(windows_menu), TRUE, &i);
}



I actually want to use something like the following call to get WA_MENUITEM_ID but it is crashing Winamp every time. Can someone explain this.
code:

DWORD WA_MENUITEM_ID = SendMessage(plugin.hwndParent,WM_WA_IPC,(WPARAM)9999,IPC_REGISTER_WINAMP_IPCMESSAGE);



I am now working on activating this mode when I click on the menu entry (or via a hotkey). Let's see how it goes.
Oh, and I can not find wa_hotkeys.h in the sdk ...
rahulthewall is offline   Reply With Quote
Old 18th May 2010, 15:03   #6
DrO
 
Join Date: Sep 2003
Posts: 27,873
you're incorrectly calling IPC_REGISTER_WINAMP_IPCMESSAGE, it needs to be done like DWORD WA_MENUITEM_ID = SendMessage(plugin.hwndParent,WM_WA_IPC,(WPARAM)&"choose_a_new_string",IPC_REGISTER_WINAMP_IPCMESSAGE); (will amend the internal copy of wa_ipc.h to better explain that).

i've attached a copy of wa_hotkeys.h and does look like it's missing from the sdk but will have to double-check/fix that if it's broken in the build scripts.

-daz
Attached Files
File Type: h wa_hotkeys.h (3.7 KB, 186 views)
DrO is offline   Reply With Quote
Old 18th May 2010, 15:25   #7
rahulthewall
Junior Member
 
Join Date: Apr 2010
Posts: 23
Thanks - it is fixed now.

Another question about this menu thing - I want the menu items to appear after the Shuffle and Repeat items under the play menu. Currently, I am doing it with this call:

code:
InsertMenuItem(windows_menu, (GetMenuItemCount(windows_menu) - 3), TRUE, &i);


Is there another way of getting the count of items up to the Shuffle menu entry ...

Thanks a lot again for the help.
rahulthewall is offline   Reply With Quote
Old 18th May 2010, 15:31   #8
DrO
 
Join Date: Sep 2003
Posts: 27,873
the other way would be to get the menu handle and enumerate through the menu items until you get the position you want by checking the id of the menu item being looked at in the enumeration.

also, if you're only adding it on that menu, that means classic skin users have no access to the menu command. the classic skin equivalent is in the options menu so would require passing -1 and doing a few GetSubMenu(..) calls to get the correct submenu item.

-daz
DrO is offline   Reply With Quote
Old 20th May 2010, 09:44   #9
rahulthewall
Junior Member
 
Join Date: Apr 2010
Posts: 23
Apologies for this incessant stream of questions. I am working on subclassing the main winamp window - and then wait for the menu item to be checked.

In the init() function I have:
code:
lpWndProcOld = (WNDPROC)SetWindowLong(plugin.hwndParent, GWL_WNDPROC, (LONG)MainWndProc);


Then I have a callback function
code:
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {

// Now what event should I expect when the menu item is clicked
// Then I change the state of the menu - add a tick
// On getting the menu item I do some stuff

// return to the main winamp process when I am done
return CallWindowProc(lpWndProcOld,hwnd,message,wParam,lParam);
}



Tell me, does this work flow make sense - and what event to expect when the menu item is clicked.
rahulthewall is offline   Reply With Quote
Old 20th May 2010, 10:24   #10
DrO
 
Join Date: Sep 2003
Posts: 27,873
(i'm guessing you've not done much Win32 coding before so...) you'd be expecting a WM_COMMAND with LOWORD(wParam) == WA_MENUITEM_ID and then you can do what you want to do.

also, as you're doing a sublcass, you need to make sure you don't break the unicode taskbar text support (for 5.34+ clients) by using something like the following (details on why are in the gen_lang_example project)
PHP Code:
WNDPROC SetWinampWndSubClass(HWND winampWNDPROC newproc){
    if(
IsWindowUnicode(winamp)){return (WNDPROC)SetWindowLongPtrW(winamp,GWLP_WNDPROC,(LONG_PTR)newproc);}
    else{return (
WNDPROC)SetWindowLongPtrA(winamp,GWLP_WNDPROC,(LONG_PTR)newproc);}

-daz
DrO is offline   Reply With Quote
Old 20th May 2010, 12:56   #11
rahulthewall
Junior Member
 
Join Date: Apr 2010
Posts: 23
Man, you're the star.

This is the first time that I am indeed coding on win32 - all my previous experience is with Unix.

And now I realize that all these manipulation with menus is actually part of the win32 environment ... so I guess I will look there in more detail for solution to my problems.

Thanks again for the help.

P.S. Where can I find this gen_lang_example - I can't seem to find it in the SDK ...
rahulthewall is offline   Reply With Quote
Old 20th May 2010, 13:13   #12
DrO
 
Join Date: Sep 2003
Posts: 27,873
is one of the sticky forum threads -> http://forums.winamp.com/showthread.php?t=316420 and although it's for showing how to use the 5.5+ language support it also has some relevant information about making general purpose plug-ins like the subclassing thing.

-daz
DrO is offline   Reply With Quote
Old 2nd June 2010, 23:53   #13
rahulthewall
Junior Member
 
Join Date: Apr 2010
Posts: 23
OK, first the good news. After reading your gen_lang_example and going through the WIN 32 API I have nailed down all the events - Stop, Pause, Play, Next, Previous and can catch them all perfectly. But of course, there has to be a little snag - and it has arrived in the form of catching the menu events.

Menu creation code
PHP Code:
HMENU windows_menu = (HMENU)SendMessage(plugin.hwndParentWM_WA_IPC, (WPARAM)2IPC_GET_HMENU);
    
HMENU alt_menu = (HMENU)SendMessage(plugin.hwndParentWM_WA_IPC, (WPARAM)0IPC_GET_HMENU);
    if (
windows_menu) {
        
        
WA_MENUITEM_ID_1 SendMessage(plugin.hwndParentWM_WA_IPC, (WPARAM)&"museek_database"IPC_REGISTER_WINAMP_IPCMESSAGE);
        
WA_MENUITEM_ID_2 SendMessage(plugin.hwndParentWM_WA_IPC, (WPARAM)&"museek_playlist"IPC_REGISTER_WINAMP_IPCMESSAGE);
        
fileDebug << WA_MENUITEM_ID_1 << "\n";
        
fileDebug << WA_MENUITEM_ID_2 << "\n";
        
int window_visible 0;

        
MENUITEMINFO i = {sizeof(i), MIIM_ID MIIM_STATE MIIM_TYPEMFT_STRINGwindow_visible MFS_CHECKED 0WA_MENUITEM_ID_1};
        
i.dwTypeData SMART_SHUFFLE_LIBRARY
        
InsertMenuItem(windows_menu, (GetMenuItemCount(windows_menu) - 3), TRUE, &i);
        
InsertMenuItem(alt_menu1TRUE, &i);
        
        
MENUITEMINFO j = {sizeof(j), MIIM_ID MIIM_STATE MIIM_TYPEMFT_STRINGwindow_visible MFS_CHECKED 0WA_MENUITEM_ID_2};
        
j.dwTypeData SMART_SHUFFLE_PLAYLIST
        
InsertMenuItem(windows_menu, (GetMenuItemCount(windows_menu) - 3), TRUE, &j);
        
InsertMenuItem(alt_menu1TRUE, &j);
        
    } 
Trying to catch menu events:
PHP Code:

DWORD tmp 
LOWORD(wParam);

    if (
message == WM_COMMAND && tmp == WA_MENUITEM_ID_1) {
        
fileDebug << "Smart Shuffle Music Library" << "\n";
    }

    if (
message == WM_COMMAND && tmp == WA_MENUITEM_ID_2) {
        
fileDebug << "Smart Shuffle Current Playlist" << "\n";
    } 

So, where is the mistake? Have I missed something in the API?
rahulthewall is offline   Reply With Quote
Old 3rd June 2010, 00:24   #14
rahulthewall
Junior Member
 
Join Date: Apr 2010
Posts: 23
Solved it, the following way of comparing did the trick:

PHP Code:
    if (message == WM_COMMAND && wParam == (WPARAM)WA_MENUITEM_ID_1) {
        
fileDebug << "Smart Shuffle Music Library" << "\n";
    }

    if (
message == WM_COMMAND && wParam == (WPARAM)WA_MENUITEM_ID_2) {
        
fileDebug << "Smart Shuffle Current Playlist" << "\n";
    } 
rahulthewall is offline   Reply With Quote
Old 8th June 2010, 15:05   #15
rahulthewall
Junior Member
 
Join Date: Apr 2010
Posts: 23
Further questions:

Is there a notification sent when the track finishes playing. I know there is the notification IPC_PLAYING_FILE sent when a new file starts playing. However, I want to a notification when a file has finished playback so that I can preempt the next file that will be played.

The primary aim here is to preempt the file that would be played next - I am just looking ways to achieve this through the Winamp API.

Secondly, what are the ways to interact with the media library and the playlist. I want to load the entire library as a playlist and then play any song from this playlist at random. In which files would I find controls for this?

Thanks a lot for the answers
Rahul
rahulthewall is offline   Reply With Quote
Old 8th June 2010, 15:33   #16
DrO
 
Join Date: Sep 2003
Posts: 27,873
there's WM_WA_MPEG_EOF (though it's not guaranteed to be done for all formats)
or
IPC_CB_MISC and the IPC_CB_MISC_STATUS event (is sort of documented in wa_ipc.h)
or
IPC_GET_NEXT_PLITEM (though if you use that and override the return value then you'll break the other playback queue feature so would need to use api_queue in that case to allow both to work together)
or
IPC_STOPPLAYING (see details after though its a 5.57+ api and may change in future versions just not sure as it's a new api).

PHP Code:
typedef struct {
  
int last_time;
  
int g_fullstop;
stopPlayingInfoStruct;

#define IPC_STOPPLAYING 3043
/* (requires Winamp 5.57+)
** This is a notification message sent to the main Winamp window by itself whenever
** playback is stopped either when file playback ends or the user stops playing.
**
** if(message == WM_WA_IPC && lparam == IPC_STOPPLAYING)
** {
**   // do what you need to do such as logging where playback was
** }
*/ 
for the ml interaction there is gen_ml/ml.h or gen_ml/ml_ipc_0313.h though what apis you use depends on the client version being targeted/run under. this post may be of use -> http://forums.winamp.com/showpost.ph...1&postcount=14

-daz
DrO is offline   Reply With Quote
Old 8th June 2010, 18:25   #17
rahulthewall
Junior Member
 
Join Date: Apr 2010
Posts: 23
Thanks again for the amazingly quick reply. IPC_STOPPLAYING was not documented in wa_ipc.h so I put it in my own header file. Now, as long as the code does not change, I guess I should be OK - however, I don't see it as a problem to change the code if the plugin stops working after an API change.

I will now look into managing the media library and the playlists.

Once more, thanks again for the help - I hope that the community would also help us in testing the plugin once we are ready with a usable version of it.
rahulthewall is offline   Reply With Quote
Old 8th June 2010, 19:12   #18
rahulthewall
Junior Member
 
Join Date: Apr 2010
Posts: 23
I spoke too soon - it looks this like IPC_STOPPLAYING breaks the other events in my message loop. Below is how I have my message loop setup:

PHP Code:
LRESULT CALLBACK WndProc(HWND hwndUINT messageWPARAM wParamLPARAM lParam)
{
    
LRESULT ret CallWindowProc(lpWndProcOld,hwnd,message,wParam,lParam);

    if (
message == WM_WA_IPC && lParam == IPC_PLAYING_FILE) {
        
        
#ifdef ENV_DEBUG
            
fileDebug << "New Song Started" << "\n";
        
#endif

        
return ret;
    }    

    if (
message WM_WA_IPC && lParam == IPC_STOPPLAYING) {
        
        
#ifdef ENV_DEBUG
            
fileDebug << "Song Stopped Playing" << "\n";
        
#endif

        // return ret;
    
}
    
     
    if (
message == WM_COMMAND && wParam == WINAMP_BUTTON5) {
        
        
#ifdef ENV_DEBUG
            
fileDebug << "NEXT" << "\n";
        
#endif

        
return ret;
    }
    
    return 
ret;

So when I have the condition for IPC_STOPPLAYING the events "Next" and "Previous" are not registered.

Do tell me whether this is how it will be - otherwise I will have to change my plugin a little - if IPC_STOPPLAYING is the only event I get on song change - I can still think of a way to make the plugin work (without any changes in the initial plan).
rahulthewall is offline   Reply With Quote
Old 8th June 2010, 20:24   #19
DrO
 
Join Date: Sep 2003
Posts: 27,873
from what i'm looking at, IPC_STOPPLAYING is sent as Winamp is closing things at the end of playing a file (or so should be) but i can't see anything which would cause it to block the WM_COMMAND events from being received.

IPC_CB_MISC with wParam = IPC_CB_MISC_STATUS is fired off at the same time as a non-blocking notification so should be more reliable to use for detecting the change/ending of a song.

i'm just not sure really what you're trying to achieve as overriding playback (so cross-fading, etc works completely) can only reliably be done in one place and those two messages aren't it.

-daz
DrO is offline   Reply With Quote
Old 8th June 2010, 21:15   #20
rahulthewall
Junior Member
 
Join Date: Apr 2010
Posts: 23
Let me explain what I am trying to achieve.

We have a project (http://musicexplorer.org/page/) where we represent songs as points in a 32-coordinate space. We want a similarity based shuffle feature for winamp that utilizes this map.

The current idea (of implementation) assumes that when a song finishes playback (either it ends or the user presses skip) the next song that is played is similar to the song that was played previously, based on how long the user listened to that song. If for example, the user was listening to song A of length 200s and he/she listens to that songs for only 1s, the next song that is played will be quite dissimilar to song A. On the other hand, if the user listens to this song for say 190s the next song will then be similar to song A.

To achieve this, I only need the time difference between the events "Song Start" (IPC_PLAYING_FILE) and "Song end"(IPC_STOPPLAYING) since the event IPC_STOPPLAYING is received even when the next/previous button is pressed. I have already set up the timer and can calculate the time difference between these two events.

However, there is a problem with calculating the length of the track. Currently, I have this set up in the following way (in the same message loop that I posted in my earlier post)

PHP Code:
    if (message == WM_WA_IPC && lParam == IPC_PLAYING_FILE) {
        
        
trackTime SendMessage(plugin.hwndParentWM_WA_IPC1IPC_GETOUPUTTIME);
        
#ifdef ENV_DEBUG
            
fileDebug << "New Song Started" << "\n";
        
#endif

        
return ret;
    } 
For some reason, this does not work with the first song that I play. I go my music library and double click on an item (song) and then press next. It shows the time difference for this first song but the total time for the first song is -1 (error code).

Can you please explain what is going wrong here.

Thanks a lot for your help, and I hope that my post has made clear what I am trying to achieve with this plug-in.
rahulthewall is offline   Reply With Quote
Old 8th June 2010, 21:28   #21
DrO
 
Join Date: Sep 2003
Posts: 27,873
it's too late now to do it (gone 10pm here) but i'll sort out a basic plug-in that'll do the required detection as its easier to code something and know it works than try to explain it.

-daz
DrO is offline   Reply With Quote
Old 11th June 2010, 06:28   #22
rahulthewall
Junior Member
 
Join Date: Apr 2010
Posts: 23
Hey, sorry to bug you but have you made any progress regarding this. I really do appreciate your help and time in this regard.

Thanks
Rahul
rahulthewall is offline   Reply With Quote
Old 11th June 2010, 09:37   #23
DrO
 
Join Date: Sep 2003
Posts: 27,873
i've not had a chance yet, will be either later today or monday that i'll have something sorted out.

-daz
DrO is offline   Reply With Quote
Old 11th June 2010, 12:26   #24
rahulthewall
Junior Member
 
Join Date: Apr 2010
Posts: 23
Thanks a ton!
rahulthewall is offline   Reply With Quote
Old 14th June 2010, 12:43   #25
DrO
 
Join Date: Sep 2003
Posts: 27,873
what i've attached will detect a number of different states (start playing, use changes playback, normal advance, stopping, pausing, un-pausing) and will show how long the file has actually been played for (is a bit rough but it'll do for an example).

i've not used IPC_STOPPLAYING as with the use of IPC_CB_MISC/IPC_CB_MISC_STATUS for most of the detection, there's no need to add in more version dependencies in the example. and i use GetTickCount on things as there can be a delay with what Winamp's output plug-ins report and hence why IPC_GETOUPUTTIME can be dodgy at times) - all depends on what's going through Winamp's message loop at the time and what format is being played (WMA is notorious for taking a while to start actually playing especially with DRM'd files).

anyway, i hope the code will make sense and could even be a decent basis for the now-playing logger plug-ins which keep appearing.

-daz
Attached Files
File Type: 7z gen_play_state_test.7z (3.2 KB, 160 views)
DrO is offline   Reply With Quote
Old 16th June 2010, 07:03   #26
rahulthewall
Junior Member
 
Join Date: Apr 2010
Posts: 23
Thanks a ton for your code, I am going to try it out with my code now. Hopefully, things will be fixed. Again, thanks a lot.

Thanks a lot, I will try it out to see how it works. Thanks a lot again.
rahulthewall is offline   Reply With Quote
Reply
Go Back   Winamp & Shoutcast 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