View Full Version : Winamp Scripting
shaneh
28th August 2004, 05:21
Just a quick update cause I have to leave. This is the start of some scripting support I am adding to Winamp. You cant do much with it yet, and it can only run one script at a time (it currently stays running to recieve events, so the scripting object isnt deleted thus not freed etc). And is a fair bit buggy when the script borks.
Anyway, paste this into the scripting window to see it at least do something. Requires Word.
Set wd = CreateObject("Word.Basic")
wd.appshow
wd.filenew
WAobj.SayHi
WAobj.Play
Sub WAObj_ChangedTrack
wd.Insert "New Track...."
End Sub
Obviously this will be much more complete over time, and allow heaps of stuff. In particular the ability to run scripts concurrently, and to be invoked from menus with arguments etc.
saivert
30th August 2004, 07:36
The plug-in doesn't appear to be loaded. I tried to run "REGSVR32 gen_script1.dll", but that didn't work. Any suggestions?
shaneh
30th August 2004, 07:54
Theres no registering involved, its all self contained. The type library is a resource in the .exe.
Its probably just a weird version thing. Im using xp sp2 with vs.net 2003 installed. Thus it uses all the latest CRTs etc.
Ill update a new version, its a bit buggy though. It does allow you to do some stuff with the playlist though:
Like;
set x = playlist
msgbox x(3)
msgbox playlist.count
for each track in playlist
msgbox track
next
and so forth. Im using standard names for automation where possible so you can use some of the nicer things in vbscript etc. (note it currently crashes for some reason when using the 'for each' stuff).
It currently leaks memory just to make life easier, I'll fix it up later. It kills the object after the script is finished currently so events will appear not to be working.
saivert
30th August 2004, 08:23
I'm using Windows XP Professional with SP-1 only (Build 2600.xpsp2.030422-1633: Service Pack 1) as reported by winver.
It says xpsp2 cos' of Windows Update. I have not installed the complete Service Pack 2 (standalone installer), which is not out yet. And I don't have "vs.net 2003" either. What's the deal??
shaneh
30th August 2004, 08:27
The standalone installer for sp2 has been out for some time... I installed it a few weeks ago. MS has it on their site.
But I doubt that would be the problem, its probably the lack of vs.net2003. Do you have MSVCR71.DLL in your windows system directory? (note the '1'). It requires that at the moment, I'll link it statically later on, or use the older CRT.
shaneh
30th August 2004, 10:15
Heres a version that links msvcr71 statically so the dll isnt needed. (the .dll should be able to be installed with the .net framework if you want it). It also fixes the crash when using 'for each'. Events will work in this one too.
EDIT: removed some .reg stuff form the .dll which wasnt needed. and fixed some windowing problems.
saivert
30th August 2004, 11:12
Thank! This helped a lot.
I didin't find SP-2 on Windows Update. They claimed it would be installed automatically if I had Automatic Updates turned on for Windows Update. I'll search for it on their search page. Maybe you have the URL??
You are using IActiveScript and IActiveScriptSite right?? Or are you just using "Microsoft Script Control" ActiveX Control?
shaneh
30th August 2004, 11:15
http://www.microsoft.com/downloads/details.aspx?FamilyId=049C9DBE-3B8E-4F30-8245-9E368D3CDB5A&displaylang=en
Its 270mb though, the auto-update would come in at less than half that. But I have bandwidth to burn and want to slip stream it so I dont have to redownload it again if i ever format or install another machine.
saivert
30th August 2004, 11:18
You are on, right this time with me huh!! Noticing the quick reply...
Can you explain what the lower edit box is for??
shaneh
30th August 2004, 11:26
I was using it for testing running multiple scripts, its not used at all at the moment. When I start adding some multi-thread support I will make use of it. The final version wont use it at all, but will load stuff up from 'startup_xxx.vbs' and 'changedtrack_xxx.vbs' and 'playlistaction_xxx.js' files etc.
At the moment I am trying to get the object design done, its a bit tricky. For example enumerating the track list is complicated by the fact that the list can change at any time. I can cache a copy, but it could potentially be quite large. Currently the 'mediaitem' objects are created on demand, which is nice, but is difficult to manage when the playlist changes.
The same will be true of things like 'send to' selecions, media library queries etc.
The thread stuff shouldnt be too difficult, I already know how im going to do it, just a matter of actually doing it.
As for the replies.. I have my messenger account hooked up to the replies so I get a notification when theres a reply to my thread.
saivert
30th August 2004, 11:38
Can you compile a list of the methods and properties of WAObj, as I don't have OleView (VC++ not installed at school computers).
shaneh
30th August 2004, 11:47
Theres not really any at the moment, just 'Play' and 'SayHi'. Plus a 'ChangedTrack' event - I may change this to an event on the playlist object instead. The problem with that is it requires a 'playlist' object to be created - and I want to keep the objects as being created dynamically on demand so they arent created if theyre not needed.
Then again, theres likely to be only a couple objects that would need to be created like this, so the overhead would be low...
Adding new methods takes about 5 seconds, most of them are just sendmessage calls. I want to get the design done properly first.
The hard part is managing objects, and internal allocations etc. The playlist problem is a good example, I think I will just use a snapshot when the enumerator is first accessed.
+ the WAObj is going to be renamed the 'Application' object, in keeping with standard naming conventions.
EDIT: There is aslo a 'playlist' property on the waobj. On the playlist object there is a 'Item' 'Count' and a enumerator. The Item takes an index (can also be used like - playlist(index)) which returns a 'MediaItem'.
Currently the 'MediaItem' just has a 'Name' property. But I guess it will have stuff like 'Title' , 'Play()' etc.
I can submit the .tlb file, but it should be a resource of the .exe anyway.
saivert
30th August 2004, 13:34
How do I get the title and the index of the current playing item, for use in the event WAObj_ChangedTrack.
Sub WAObj_ChangedTrack
MsgBox "Playing " & WAObj.CurrentSong
End Sub
shaneh
30th August 2004, 13:43
You cant :P
Not yet anyway. As I said, its just a prototype to show it can be done, not that it is actually done.
Eventually you will be able to do stuff like
playlist.currentitem
or
playlist.getcurrent()
or
playlist.item(playlist.currentpos())
or the current playlist position will be passed in the changedtrack event.
or whatever I choose to do.. theres many different ways of doing things. Once I get more things done, Ill post a complete list of the object model.
shaneh
31st August 2004, 05:14
A small update with some more interesting stuff. Has the ability to run and stop scripts to make life easier.
added:
position property to playlist get/set
position property to media items
filename property to media items
title property to media items
ATFString method to media items
An nice example of it in action:
------
Set ieo = CreateObject("InternetExplorer.Application")
ieo.visible = true
Sub WAObj_ChangedTrack
ieo.Navigate2 ("http://www.audioscrobbler.com/music/" + playlist(playlist.position).ATFString("%artist%"))
end sub
------
Will navigate IE to the artist page on Audioscrobbler on every song change. You could do any action you want on any song with any ATF stuff with whatever event. But this is just a nice example. I'll write something up which parses the page and attempts to enqueue the top song later on.
Another simple example:
Set wd = CreateObject("Word.Basic")
wd.appshow
wd.filenew
Sub WAObj_ChangedTrack
wd.insert playlist(playlist.position).ATFString ("%artist% - %album% '('%filename%')'") + vbNewLine
end sub
With ATF, a lot of possibilities already exist, so I will work on getting the threading and loading from files working soon. As well as adding items to the playlist right click and send to menu.
saivert
31st August 2004, 10:35
More examples
Const ForReading = 1, ForWriting = 2, ForAppending = 8
Const LogFile = "c:\songlog.txt"
Set fso = CreateObject("Scripting.FileSystemObject")
Sub WAObj_ChangedTrack
Dim s, text
s = playlist(playlist.position).ATFString("%artist% - %album% '('%filename%')'")
If Not fso.FileExists(LogFile) Then
Set text = fso.CreateTextFile(LogFile)
Else
Set text = fso.OpenTextFile(LogFile, ForAppending)
End If
text.WriteLine s
text.Close
End Sub
Suggestion
Why not putting error messages in the lower edit box, instead of calling MessageBox() all the time. Very nasty if script contains a lot of errors (not that I have a lot of errors in my scripts).
shaneh
31st August 2004, 10:43
That box wont exist at all eventually, or even the dialog. Well I might have one that could be called up for testing or whatever. If you want to avoid errors, just put
On Error Resume Next
At the start, or make your own error handler. I will probably make some kind of console output method for use by scripts evenutally though.
There still the complicated matter of events from dynamically created objects. (ie handling events on objects create by 'createobject'). This is a known 'problem' that involves a few different solutions, none of which are that great.
saivert
31st August 2004, 11:14
Here is my final (for now) script:
Const ForReading=1, ForWriting=2, ForAppending=8
Const LogFile="c:\songlog.txt"
Const FormatText="$if(%title%,[%artist% - ]%title%,$filepart(%filename%))"
Set fso=CreateObject("Scripting.FileSystemObject")
Set ieo=CreateObject("InternetExplorer.Application")
ieo.Navigate2("about:blank")
ieo.visible=True
Sub ShowPlaylist
Dim s, i
i=1
For Each file In playlist
s = s & "<br/>" & vbCrLf & i & ". " & file.ATFString(FormatText)
i = i + 1
Next
' The following line gives error. Why??
ieo.document.write("<pre>")
ieo.document.write(s)
ieo.document.write("<br/>" & vbCrLf)
ieo.document.write("<br/>" & vbCrLf)
ieo.document.write("Tracking played items:" & "<br/>" & vbCrLf)
End Sub
ShowPlaylist
Sub WAObj_ChangedTrack
Dim s, text
s = playlist(playlist.position).ATFString(FormatText)
If Not fso.FileExists(LogFile) Then
Set text = fso.CreateTextFile(LogFile)
Else
Set text = fso.OpenTextFile(LogFile, ForAppending)
End If
text.WriteLine s
text.Close
ieo.document.write(s & "<br/>")
End Sub
1. Why can't I write ieo.document.write("<pre>")?
2. Do you have a limit on how much script code to write?
3. And why do you have to use () around parameters when it's not on the right side. Like:
' Here it is neccessary with the "()"
Dim var
var = function("param", 23)
' Here it is *not* neccessary:
function "param", 23
4. Please put the Scripting dialog inside the preferences, or put it inside a embedWindow thing (skinned frame).
shaneh
31st August 2004, 12:27
Nice script, keep in mind this is just preview stuff though, so its just for playing with at the moment.
I had to replace
If Not fso.FileExists(LogFile) Then
Set text = fso.CreateTextFile(LogFile)
Else
Set text = fso.OpenTextFile(LogFile, ForAppending)
End If
with just
Set text = fso.CreateTextFile(LogFile)
to get it working though. Dunno vbscript that well, so Im not sure what the problem was. Ive got a version which outputs the error and line etc on the error which makes it easier to find bugs in scripts. Id like to make a similar script which highlights the current item and outputs album covers etc. its easy enough using %dir%\folder.jpg.
1. I dunno, it worked ok for me - try removing some other lines, its possible its just too much code for the buffer.
2. 1024 bytes currently, Ill increase this, but there wont be a limit eventually, it will just allocate as much space as necessary for the file.
3. I dunno, some vbscript quirk. vbscript.dll does all the parsing of code, I just handle my own object.
4. The dialog will dissapear completely and I will just load scripts from files. I wont waste time for now making it look pretty. There will be a dialog you can invoke which will list all the running scripts and let you stop them etc. Plus it will let you start new scripts.
Please dont view the interface as any indication of the finished project, its just a quick hack to expose what can potentially be done.
PS. I found John's site which has the source to Winamp COM.
http://www.adcock8.freeserve.co.uk/
It probably has some helpful stuff in there, but it seems quite different to my implementation, so I cant make too much use of it.
shaneh
31st August 2004, 12:41
I just doubled the buffer to 2048 bytes, your script runs fine with this new buffer. So it was just hitting the limit. You can try it out with this version with a bigger buffer.
shaneh
2nd September 2004, 11:06
Have now modified it to allow getting the selected items. So you can now process items that are selected and do whatever you like on them. With a bit of polish this would already be quite a useful plugin, but I will work on making it more complete.
While you can do 'system' things on the items, it would also be useful to do 'winamp' things on the items (ie, remove from the playlist, randomize selection etc).
-------
k = playlist.getselection()
msgbox "You selected " + cstr(ubound(k,1)) + " items"
for each g in k
msgbox CStr(g.position) + ". " + g.ATFString("%title% / %album%")
next
shaneh
2nd September 2004, 11:10
forgot the attachment
Lord Darius
2nd September 2004, 14:59
hi there, i planned to offer scripting support to Winamp too, but at first i had thought about using SpiderMonkey as a scripting engine (Mozilla's javascript), and eventually switched to LUA.
Unhappily, my job has been taking too much time, so that project is stalling in a very early stage.
SM or LUA would allow a feature that may not be available with the VB runtime: running scripts in a sandbox disallowing unsecure operations in a customizable way.
I don't want to download a script that will install some spyware using kinda obfuscated code like VB code can be (especially with CreateObject() )
shaneh
2nd September 2004, 16:19
Hey,
adding scripting support using windows script hosting is quite easy, and flexible. Its literally one or two lines to add support for javascript, perl and any other language (once you have the support for actually hosting the scripting engine). Plus the whole 'createobject' thing makes it very powerful indeed.
Also, it has a quite extensible security model, IE uses the same one. Basically you can implement your own security manager and can choose to allow or disallow object creation at runtime. This allows you to let 'safe' objects the ability to still be scripted (ie like 'safe' activex objects in IE), or you can loosen the restrictions and let file system objects etc be created if necessary.
I have already done this in 'Winamp HTML', however I went out of my way to weaken the security to allow unsafe stuff.
My reasoning for this is there is already safe scripting support in Winamp, through wasabi or whatever. Anything interesting requires some kind of permissions.
If I wanted it to be truly safe, I would have to restrict it to just stop and play type stuff, with no execution, or even changing meta data in the media library, it would be quite an undertaking to make it truly safe. Plus this is already possible with modern skin scripting.
Basically I want it to be a way for people to write their own plugins or to script common tasks easily and quickly. Scripts that are actually able to do stuff. So therefore you should use the same caution installing other peoples scripts as you would plugins. Scripts certainly wouldnt be something that came bundled with skins or something like that.
Having said that, it probably wouldnt be too much trouble to at least selectivly block 'createobject' etc type stuff per script if necessary. Although I probably wouldnt bother flagging each of my objects methods as safe or not so there could still be holes.
Lord Darius
2nd September 2004, 20:35
Basically I want it to be a way for people to write their own plugins or to script common tasks easily and quickly. Scripts that are actually able to do stuff. So therefore you should use the same caution installing other peoples scripts as you would plugins.
That's exactly what i wanted to achieve with my plugin :)
I think you're very right in the way you're doing it.
To be honest I also considered using VB or JS (WSH...) but, there are two things that made be reject that idea.
1. I don't like VB and JS (that's why i also rejected SpiderMonkey) as programming languages... just personal tastes :confused:
2. It's not 100% certain that the WSH will be present on a particular windows box (i'm assuming you're actually using the Windows Script Host)
shaneh
3rd September 2004, 00:39
1. You can use any language that has an active script engine. Perl has one, and there are other languages (tcl, pascal etc). You can let the user decide which one to use by just having a standard name convention (ie .vb, .vbs, .pl).
I dont like VB that much either, but as it is MS' baby, it is the most powerful. And the more I learn about this scripting stuff, the more it makes sense to use a language such as VB (for scripting). Plus people know VBscript and JS thanks to the web and VB/VBA etc. It saves them from having to learn another language, which is kind of the point in the first place.
2. Its not actually WSH, its ActiveScript. WSH is just one host for the engine, in exactly the same way this project is a host for the engine. It would be available on any platform which has IE ~3+. Either way, you could always let people install it if they want it.
shaneh
3rd September 2004, 04:22
You may now do basic querying of the media library. I will make a much better implementation of this later on, but this one will still remain as it is still useful. It returns an array of initialised items rather than a collection to enumerate over. This isnt too efficient for large queries, but should be ok for smaller ones.
As the query returns much richer info, I will have it cache it in the items so you can obtain it without using ATFString and the like. Obviously items obtained from a media library query do not have a 'position' in the playlist.
---basic example----
Dim x, s
Set wd = CreateObject("Word.Basic")
wd.appshow
wd.filenew
wd.Insert "Songs by Metallica" + VbNewLine
mlq = medialibrary.runqueryarray("Metallica")
x = 0
s = ""
For each track in mlq
x = x + 1
s = s + track.ATFString("%album% - %title%") + VbNewLine
if x > 200 then
wd.Insert s
s = ""
x = 0
end if
next
wd.Insert s
saivert
3rd September 2004, 06:34
I have recently started out my own project called NxS Script Control. It is plug-in that uses Active Scripting like ShaneH's gen_script1.dll.
It integrates with the Winamp Preferences (adds it's own page) and you can load/save script files.
The object in script that controls Winamp is called "Winamp", and it currently has these methods:
- Play()
- Stop()
- Next()
- Prev()
- AddToLog("string to add")
It has a log list that outputs error messages and text passed to AddToLog.
I will eventually add more stuff, like in ShaneH's plug-in.
Download it and try it out...
saivert
3rd September 2004, 07:23
Here is more script for the masses!!
Dim x, s, wd
Set wd = CreateObject("InternetExplorer.Application")
wd.Navigate2("about:blank")
wd.document.write "<html><head>"
wd.document.write "<title>Winamp Media Library</title>"
wd.document.write "</head>"
wd.document.write "<body bgcolor=black text=#CEFFCE>"
wd.document.write "<p>"
k = playlist.getselection()
wd.document.write "You selected " + CStr(UBound(k,1)) + " items: "
wd.document.write "</p><p>"
For Each g In k
wd.document.write CStr(g.position) + ". " + g.ATFString("%title% / %album%")
Next
wd.document.write "</p>"
wd.document.write vbNewLine & "<table border=1>" & vbNewLine
mlq = medialibrary.runqueryarray("?")
x = 0
s = ""
For Each track In mlq
x = x + 1
s = s & "<tr>" & _
track.ATFString("<td>[%artist%]</td>[<td>%title%</td>]") _
& "</tr>" & VbNewLine
' Write out in increments of 200 songs (buffer)
If x > 200 Then
wd.document.write s
s = ""
x = 0
End If
Next
wd.document.write s + vbNewLine
wd.document.write "</table>"
wd.document.write "<p><u>Result from ping command:</u></p>"
wd.document.write "<pre>" & CatchConsoleOutput("ping localhost") & "</pre>"
wd.document.write "</body></html>"
wd.visible = True ' All written, show IE
' I just love "InternetExplorer.Application" :-)
' How to execute an application
Sub RunApp(app)
Dim WshShell
Set WshShell = CreateObject("WScript.Shell")
WshShell.Run app, 5
End Sub
' Example:
' RunApp "notepad.exe"
' How to catch output from console apps
Function CatchConsoleOutput(app)
Dim WshShell, prog, s
Set WshShell = CreateObject("WScript.Shell")
Set prog = WshShell.Exec(app)
While (prog.Status = 0) And (Not prog.StdOut.AtEndOfStream)
s = s & prog.StdOut.Read(1)
Wend
CatchConsoleOutput = s
End Function
Hope you like it...
Lord Darius
3rd September 2004, 09:44
why not take the best of all worlds and make one plugin in a collaborative effort ?
IMHO, saivert's interface is better (the one i started was basically based on the same idea).
One good thing would be to have a list of the currently loaded scripts, and be able to stop and start them at will (like in the Winbot IRC bot).
For my plugin, my intent was to implement all the functionality of the SDK through some objects (Winamp, Winamp.mainwnd, Winamp.playlist etc), plus event handling.
i also wanted the ability to be able to add dynamic extensions to the plugin, for example to add some database or networking support, for instance. I guess it's not that useful here, as Active Scripting can use COM objects :p
As for languages, it would be nice also if a different script file extension (js, vbs...) would use the appropriate engine.
Last but not least, to make this plugin really useful, even though it's the most boring part in development, a big effort should be put on documentation, else, only few people will bother trying to learn the API from samples only.
These were my 2 cts :)
shaneh
3rd September 2004, 11:58
Added a few more methods and properties. Have changed the way the runqueryarray works, it now does a standard query. So queries are now of the form:
"type = 0", "artist HAS metall" etc
I will probably put the keyword query method back in under another name.
Have changed the base object to "Application" in keeping with standard automation naming conventions.
Can now create MediaItems by using "LoadItem" and a file name. Or using "GetItem" and a filename to retrieve stuff from the media library.
ATFString can now query for media library items. (rating,playcount etc)
Added basic play,pause etc operations, and a clear method for the playlist.
I have decided that the array mechanism of doing media library queries is ok, as you need to make a copy any way in case another plugin frees your query. But I will probably add another more efficient version of the query that doesnt make a copy, for cases where you want to enumerate the results straight away, and dont need the copy sticking around to process later in an event for example.
With that in mind, I am debating the merits of multi-threading the scripts, as it would require a lot of synchronisation, and I am not sure what is and isnt thread safe in winamp, plus there is the potential for deadlocks.
As the scripts can potentially do anything, it is potentially quite dangerous to make the scripts run in a separate thread to winamp - they would be likely to conflict with other plugins. Thus they will simply run synchronously, just like normal plugins.
Note that this will still allow events and so forth to run, they will just not run simultaneously. Just like normal plugins.
-----------
@Lord Darius. As Ive said numerous times, this is not the interface the plugin will use. As it is obviously still a work in progress, while I am developing it, the first thing I need to do when I fire up winamp is type some test script and test it. This interface allows that. Files arent of any use at the moment as I am constantly changing what I am testing.
The plugin will simply load scripts from files such as:
startup_1.vbs
plscommand_Upload to Ftp.js
etc. The extension will indicate the scripting engine to use. And the plugin will pick them up and run them and add menus etc as appropriate. I will still supply I similar interface to this debug one, for testing scripts, and a means to see what scripts are currently connected for events (running) and let you stop them etc, plus let you load arbitrary scripts etc. Plus supply some kind of console ouput which you can view or hide. It will also have a browser component to it which will let you make use of the scripting inside a browser window in the media library.
But I'll say it again just to be sure. This is not the interface the final plugin will use. It is for testing purposes only, do not draw judgement on it.
As for documentation, you may load the included .tlb in an object browser (any vb/vba/vis studio/ms word type app has one) and you will see all the methods and properties. (done so far, IT IS NOT COMPLETE - testing purposes only, yada yada.).
shaneh
3rd September 2004, 13:39
This script will enqueue a random track from the artist of the current track every track change. I should probably have a test to check that it doesnt enqueue the same item. I will need to implement some ICompare type interface on the media items I guess.
If you iterate through the playlist to make sure your not adding a dupe, itd be a nice little script to generate an ever growing playlist of a selection of a couple artists.
Next up will be changing media library meta data, then working on the general interface. Then adding working on methods for manipulating 'send to' selections, then switching items about on the playlist and other less important commands. Afterwards, I will probably add an ID3 object for grabbing stuff out of those tags, prob a v2 thing. Wont be doing anything on it tomoorrow however.
----------
Sub Application_ChangedTrack
set p = playlist(playlist.position)
mlq = medialibrary.runqueryarray("artist HAS """ + p.ATFString("%artist%") + """")
if ubound(mlq,1) > 1 then
y = Int((ubound(mlq,1)) * Rnd + 1)
mlq(y).Enqueue
end if
end sub
saivert
6th September 2004, 10:35
@Lord Darius: I like the idea of a collaborative effort.
I don't know about ShaneH - He may be working best on his own,
but I would be happy If you and me decided to share code,
and create something beatuful together ..hmmm, what's that suppose to mean :)...
@ShaneH: I know that you don't intend to have a dialog in a finished version.
It will basically be the same with NxS Script Control, but I like to
give users the ability to edit and manage scripts inside Winamp, instead of
having both Explorer and Notepad open.
NxS Script Control (new version below) detects which script engine to use
by reading the script itself. The user must place a comment at the first line
to indicate which script type it is.
VBScript example:
'@Language = VBScript
JScript (JavaScript) example:
/*@Language = JScript*/
If such a comment isn't found then it will use the file's extension to select
the engine. But this sucks since I would have to maintain a list of known
extension like vbs, js, psc (PersScript) and more.
You could also just try to parse the script using one engine after the other until
an engine parsed it successfully, but then all scripts would have to be flawless.
I will always include the source code with my plugins keeping it open-source.
@Lord Darius: Please take time reading the source for NxS Script Control, and
give me feedback (private message on forum or e-mail) on it. It will help me improve my
coding skills and who know, maybe you will learn something too...
shaneh
6th September 2004, 11:28
+settimeout method, used for callback on a timeout. Timer is cancelled after triggered.
ie.
settimeout 5000, getref("myfunc")
sub myfunc
msgbox "Called"
end sub
+quit method
Used to terminate the script and stop listening for events.
+Loads items from files plugins\scripts\startup_*.vbs and playlist_*.vbs. Items in startup* are run at startup, items in playlist* are run when selected from the playlist 'Scripts' menu.
+Experimental 'attachevents' method for binding the events of a dynamically created object. Works similar to 'connectobject' of wscript. Its use is not recommended at the moment, and it wont work with IE either.
ie.
Set calobj=CreateObject("MSCal.Calendar.7")
attachevents calobj, "CALE"
calobj.nextday
sub CALE_AfterUpdate
msgbox "calendar event"
end sub
+changed 'stop' to 'stopplayback' due to global name conflict
+Removed dialog for now, just uses files atm.
+enumerator on the medialibrary. Can also get any item in the media library through Item(). ie.
msgbox medialibrary(123).Title
+Can read and change rating and playcount through the rating propery of media items
+alubm,artist,title is cached when mediaitem is created through a media library query
There is still lots of static buffers and globals etc which need to be cleaned up. Plus an interface for managing scripts (editing,running,stopping etc). I may put some check marks against the menu items of currently running scripts to simplify the interface, so you can start and stop them easily.
shaneh
7th September 2004, 15:23
+Basic hot key support. Files named hotkey_*.vbs will be registered as hot key runnable. I will add a 'registerhotkey' type message later, with a callback for scripts that stay running.
[I will probably remove the hotkey_* type files, and just register all playlist_*/sendto_*/menu_* etc files as hot key assignable instead).
+Canceltimer(timerid). You can cancel a timer set by 'settimeout' by using the id received from 'settimeout'.
+playlist.Deleteindex - remove an item from the playlist
+playlist.Swapindex - swap two indexes in the playlist
+mediaitem.insert(index) - insert the item at the specified position in the playlist
+much improved 'changedtrack' event detection. avoids dupes without having to do filename comparisons etc.
Some other example scripts, including one which makes the playcount only increment if its been played for over 9 seconds.
shaneh
9th September 2004, 15:59
Fixed many static buffers, much better loading from file support. Should support basically any size file. Removed hotkey_* type, all playlist_* files can be assigned hot keys.
Improved visual display of items in playlist menu.
Improved loading of playlist_* named files.
Fixed some internal object management and the way scripts quit.
+Added 'lastplay' property
+Getting selected items now re-parses the 'length' of playlist items correctly so it doesnt get reset.
(if the playlist hasnt yet loaded the extended file information, it will query the ML to avoid having ugly titles).
Quite a few example scripts, some of which make use of a fairly generic quicksort algorithm which has been used to sort selected playlist entries by rating, playcount, last played etc. Its a useful bit of script for sorting stuff in the playlist in general - it could use a little bit of tweaking but its generally pretty reasonable.
Plus some examples to just randomize a selection, reverse a selection, 'preview' a selection etc.
neFAST
9th September 2004, 17:30
[edit]
hello again,
I'd like to know if their a command the results of a quey in the library ?
In fact I'd like to export my songs list but this MyFile.WriteLine(track.ATFString("%artist% - %album% - %tracknumber% %title%"))
gives me this :
Zero 7 - When It Falls - 11 Morning Song
Zero 7 - When It Falls - 10 In Time
Zero 7 - When It Falls - 09 Look Up
Zero 7 - When It Falls - 08 Speed Dial No 2
Zero 7 - When It Falls - 07 The Space Between
Zero 7 - When It Falls - 06 When It Falls
Zero 7 - When It Falls - 05 Over Our Heads
Zero 7 - When It Falls - 04 Passing By
Zero 7 - When It Falls - 03 Somersault
Zero 7 - When It Falls - 02 Home
Zero 7 - When It Falls - 01 Warm Sound
Zebda - Utopie D'occase - 13 Le Répertoire
Zebda - Utopie D'occase - 12 Le Paranoïaque
Zebda - Utopie D'occase - 11 Le Bonhomme Derriè
...
so I'd like to kwno how winamp chose the order of the results of a query !
My other questions are : what does "ATFString" do ? And how can i make my vbs in a standalone script ?
Sorry for the "newbie inside" style !
shaneh
10th September 2004, 00:50
The results from the media library are just returned as given by the media library, as far as I know there is no way to specify the sort order. The results will need to be sorted after you get them. I will write a quick script to demonstrate how to sort them, it is not too difficult.
If they are already in exact reverse sort order, you could always work your way backwards from mlq.Count to 1. Otherwise, if each item is on its own line, you can just run it through the 'sort' command and it should work fine.
ATFString takes a filename and a format string and parses it through 'advanced title formatting', similar to that used in the playlist. The filename is taken from the 'mediaitem' it is operating on. My "toaster" plugin has a readme which explains in more detail all the available tags etc.
Because items like 'album' 'artist' and 'title' are cached after a media library query, you are actually better off using:
track.artst + track.album + track.ATFString("%tracknumber%") + track.title
As it will not have to re-look it up if the mediaitem (track) has come from a media library query.
You cannot currently write a script standalone, although it wouldnt be too difficult for me to implement, though I hadnt planned it. You will eventually be able to run scripts by just choosing a 'run script' command from within winamp then browsing for the file, if that is all you are after. For now just call it "playlist_whatever.vbs" and run it from the playlist menu.
neFAST
10th September 2004, 01:02
Thanks for the answer !
In fact I need the export to be a little quicker cause it takes something like 3mins for 16000 tracks.
And I think the quicksort could make this even longer !
I'm gonna test your trick "track.artst + track.album" to improve exporting time nad I'll tell ya.
in fact if I have perfect reverse order it's not a problem cause the export file is parsed with a php script. I just need to know it, that's why i did ask how the results are returned.
COuld you (quickly) tell me what does your plugin really do ? Is it something like a functions library ?
Plugins are in C++, aren't they ? and scripts in vb ...
Last question : %length% return length in seconds and *three* decimals !!! Is there any way to get h:m:s ?
And again : thanx !!
shaneh
10th September 2004, 01:15
Use lengthf as outlined in the Toaster readme. You said you just wanted to do a one time export, so therefore why does the time it takes matter? (remember to put a 'quit' statement after the export otherwise the script keeps running).
3 mins is quite slow, but I guess it depends on your machine speed. I exported about 8,000 items to file in about 2 seconds, though I have a fairly reasonable machine. A sort would take a split second to do, try running 'sort exported.txt' and see how quick it is. (I am not sure if sort is standard on XP, but I think so, otherwise get cygwin). But still 3mins seems strange, try posting your script and I'll test it and see if its the same and see how it can be sped up.
If you are planning on doing programmatic exports regularly, then this might not be the plugin for you. It is designed for adding a quick customisation to Winamp without having to develop or install heaps of frivolous plugins. Its not really meant for use by external plugins, as they could typically do everything the script does, only faster as they dont have to parse script.
This plugin is indeed written in C++, it makes use of COM to create an instance of MS vbscript engine, and adds my own automation object to the script which can be used to control winamp. Thus allowing you to control winamp through vbscript.
neFAST
10th September 2004, 01:31
i've a 2.8Ghz so it's a bit strange.
Here's my code.
Const ForReading = 1, ForWriting = 2, ForAppending = 8
Set fso = CreateObject("Scripting.FileSystemObject")
Set MyFile = fso.OpenTextFile("C:\Program Files\Easyphp\www\songs.txt", ForWriting, True)
mlq = medialibrary.runqueryarray("type = 0")
for each track in mlq
MyFile.WriteLine(track.ATFString(track.artist + ";" + track.album + ";%tracknumber% " + track.title +";%bitrate%;%lengthf%;%year%;%genre%"))
next
MyFile.Close()
quit
in fact I wont use it regularly but something like 2 times in a week.
I have a basic knowledge in C++ (and zero experience in plugin writing) so I think you'll tell me that's it's impossible for me to rewrite it in C :)
neFAST
10th September 2004, 01:41
i reverted to "%artist%;%album%;%tracknumber%;%title%;%bitrate%;%lengthf%;%year%;%genre%"
you track.Artist gives me a lots of tag reading failure or something like that AND a chaotic sorting !
shaneh
10th September 2004, 01:44
That line should actually look like this
MyFile.WriteLine(track.artist + ";" + track.album + track.ATFString(";%tracknumber%;") + track.title + track.ATFString(";%bitrate%;%lengthf%;%year%;%genre%"))
But I see where the problem is, its actually something Ive been meaning to fix. The ATFString call should try the media library first and then try winamp itself.
The reason being that winamp will attempt to read the actual .mp3 file, especially for the 'lengthf' and 'bitrate' etc tags. I will cache more info from a media library query, and speed up the 'ATFString' call, and hopefully that will improve things.
If you remove the ATFString calls, and just use track.title, track.filename etc, you will notice that it doesnt take too long at all. ATFString() calls to stuff only in the media library (playcount, rating, tracknumber etc should be ok)
[edit] the reason for the tag reading failure etc is because you are putting track.artist inside the call to ATFString. look at my example above for how it should be.
neFAST
10th September 2004, 01:50
ok i'll try this tomorrow, it's near 4am here :)
electricmime
10th September 2004, 21:32
id like to make a script that enqueues all of an album.. or inserts an album... i know nothing about computers(well.. i dont know much)
i just edited the included scripts.. but when i try, it doesnt include the song i picked(so it enqueus/inserts the album only without the original track clicked...
i guess the ideal script for me would insert one of dros separator things(or just a normal separator thats just ------------- or whatever) and then the album INCLUDING the song i clicked, and then another separator...
would this be somehow possible
is it possible to make a script based on other plugins(jtfe queue album) or to make it somehow 'enqueue/insert and play album?'
though at the moment.. my biggest problem, is it doesnt include the song i used the script on when it inserts/enqueues album/artist
AnodA
10th September 2004, 22:36
Think the first one is on purpose.
Try this:
playlist_Enqueue album.vbs
x = playlist.getselection()
if ubound(x,1) > 0 then
mlq = medialibrary.runqueryarray("album HAS """ + x(1).album + """")
for each track in mlq
track.enqueue
next
end if
quit
Edit: The scripting is a great idea - brings a lot of fun :D
Keep on with this shaneh though DrO is afraid he'll get out of work
shaneh
11th September 2004, 01:47
I guess you could use something like:
pos = x(1).position
myitem = LoadItem("separator://")
myitem.insert(pos)
to insert a separator at the position. The reason it doesn't include the selected track is because it is already in your playlist. Just remove the
if strcomp(track.filename, x(1).filename) <> 0 then
which checks if the track about to be inserted is not the same as the first one selected.
AnodA
11th September 2004, 03:57
Is it odd that i cant get the script shortcuts to work on an old Win98 machine? Other shortcuts are working - scripts working with rightclick. All things are working on my XP machine.
(AMD-K6 200, Win98 SE, WinScript 5.6, Winamp 5.05 (clean install+script))
Any ideas about that?
shaneh
11th September 2004, 04:06
I assume you are talking about global hotkeys? Do other global hot keys work? Try removing the shortcuts, re-adding the key combination then restart winamp. Otherwise I am not sure, the scripts are invoked in an identical way as from the playlist menu. So if they work, there could be a problem with the registration of the global hotkey.
Also, many of the scripts make use of the selection rather than the current position etc, so it could be that they are running but just not getting the selection correctly. Try making a script with just a msgbox and see if its running ok.
electricmime
11th September 2004, 05:56
okay... so if i wanted it to insert the separator at the beggining of the inserted album, and then again at the end(as if to seperate it from the rest of the playlist) how would i do that... also... how would i get the script to play(like a 'insert and play') command...
so if i wanted to hit the script... and it would insert the entire album in order(including the song i rightclicked) then start playing it, all the while separating it from the playlist...
im probably asking for too much, but that would be totally awesome...
shaneh
11th September 2004, 06:02
You make use of playlist.position and playlist.count. If you enqueue something, it gets put at the end, so basically just set:
playlist.positon = playlist.count
Then enqueue everything
then "play"
Otherwise if you are inserting stuff, then just set playlist.position to wherever you are inserting, then "play".
To insert a separator at the beginning and end, just insert one before inserting everything, and after.
I'll include a script which does this with the next update. For now I am fixing ATFString which is horribly broken at the moment, when Im done it will actually work and should be quite fast too.
shaneh
11th September 2004, 10:55
+Many basic methods and properties to the base application object, media items and playlist (skin, shuffle, version, repeat, show notification etc.) Open the .tlb to see them all
+Much improved and fixed ATFString method, plus caches information better. Getting tag information after a media library query or getting the length from a playlist selection will be *much* faster.
Added another basic script for inserting all items from an artist, with a separator. Doesnt use an external plugin for the separator, just uses inbuilt support from Winamp (using x:\--------..). I think its better as it means not having another input plugin loaded and you can specify anything you want as the separator at run time. And it doesnt have a length value in the playlist. But you can edit it to use whatever you like.
Also another script to add separators before a selection of playlist entries.
removed the playlist count fixer script cause its a little buggy when you have a zero playcount.
AnodA
11th September 2004, 12:40
Er yes, global hotkeys (nstGlobalHotkeys v1.3). Other global hotkeys work. Even the most simple script doesn't work with global hotkey (only msgbox for example). Tried adding removing in all kinds of ways. So it's a problem with the registration, is it?
shaneh
11th September 2004, 13:02
I have the same version of global hot keys, and have tried this exact same version and it works fine. I used the exact same method in Toaster, have you tried that plugin? Do the hot keys work for that?
I assume you dont have any other plugins which could be interferring with it.
It seems strange, as it the standard method for registering hot keys that all the plugins in winamp would use.
The one thing I do have suspicions on is the order in which the plugins are loaded. If the global hotkey plugin isnt loaded before this script plugin is, there could be problems. Try renaming it gen_zscript.dll or gen_ascript.dll and see if it helps. If it does, I am already planning a fix that will help this and other potential problems.
EDIT: yes that seems to be the problem, the next versin will fix this. until then just rename the plugin gen_zscript.dll. Although, you shouldnt even be having the items listed in the hotkey config screen if this is the problem you are experiencing, so im not sure.
neFAST
11th September 2004, 13:40
Originally posted by shaneh
+Much improved and fixed ATFString method, plus caches information better. Getting tag information after a media library query or getting the length from a playlist selection will be *much* faster.
My god that's what I call "much improved" !!
My script now takes 3 seconds to execute instead of 3-4minutes with the old version !
Nice work Shaneh.
But I still have a problem with sorting the results, they're unfortunately not in EXACT reverse order :(
the sort function is recognize wy windows (sort export.txt scroll all the file) but do not results in a sorted file ?!
shaneh
11th September 2004, 13:46
You can just pipe the results to another file. ie
sort songs.txt > songs2.txt
You can run this from within your script using
set wsh = CreateObject("Wscript.Shell")
wsh.Run "sort songs.txt > songs2.txt"
or something like that. Otherwise, if you need more defined sorting, or dont want to use another file, you will just need to do the sorting yourself internally.
There is an example of the quick sort alogorithm in a couple of the scripts. You will need to make a few modifications to make it sort on the array returned from the querey but it is certainly possible, and wouldnt take too long. I'll include it as an example in my next update for people to look at.
neFAST
11th September 2004, 14:15
I've a little problem, it seems that track.artist track.album and %artist% return the album field while %album% doesn't return anything ???
could you check this please ?
AnodA
11th September 2004, 14:22
Some kind of strange. I did another clean install without jumpex and TControl and suddenly its working. Installed the newest version of them and its still working. Tried more of DrOs plugs, because i remebered there was a similar problem with his plugs some time ago. Problem appears again only with his lastest 'skinned prefs' plugin. But it wasn't installed before - I did a clean install, too. I'm confused. But maybe the problem was somehow at his side.
Edit:
Originally posted by shaneh
+Much improved and fixed ATFString method, plus caches information better. Getting tag information after a media library query or getting the length from a playlist selection will be *much* faster.
Yeh, it's really fast.
shaneh
11th September 2004, 14:33
@nefast: yep, oops. Theres probably a few bugs like that, I'll try squash them all over time, let me know if theres anything else strange like that. Theres a lot of different cases that need to be covered, when the media library isnt available, when the item has been created from the media library so the info has been cached, when it hasnt, when accessed through ATF, through a property etc, etc, etc.
To keep it nice and fast stuff is only loaded on demand, and when it is its cached for later, so it gets a little complicated.
I think I fixed the album/artist problem in this release.
DrO
11th September 2004, 14:35
Originally posted by AnodA
Some kind of strange. I did another clean install without jumpex and TControl and suddenly its working. Installed the newest version of them and its still working. Tryed more of DrOs plugs, because i remebered there was a similar problem with his plugs some time ago. Problem appears again only with his lastest 'skinned prefs' plugin. But it wasn't installed before - I did a clean install, too. I'm confused. But maybe the problem was somehow on his side. seeing as skinned prefs is labelled as alpha from memory you can expect some issues ;)
the order in which plugins loads can affect things if the chain of loading isn't as expected. doing a rename of the plugin or installing it again is often likely to fix the problem so that when winamp searches for the files it will find the newer one later in the process so the existing ones can be found. aren't plugins fun :)
Keep on with this shaneh though DrO is afraid he'll get out of workthis plugin is just another way to do things and i'm not afraid since i've got other projects in the works anyway :)
-daz
AnodA
11th September 2004, 14:46
Originally posted by DrO
i'm not afraid since i've got other projects in the works anyway :)
... get alphas to 1.x state for example ;)
shaneh
11th September 2004, 14:46
"the order in which plugins loads can affect things if the chain of loading isn't as expected."
Yeah, its not too hard for other plugins to affect the operation of others, or a dependence not be satisfied due to the order not being as expected. Although the plugin will enter the 'chain' at the normal time, I'll be changing it so it doesnt initialise or start running scripts until the initial plugin shakedown is complete for all plugins.
But there is stil the problem of command ids being used by other plugins. AFAIK the current standard is just use any old random spare id when adding to menus etc. If any two plugins try use the same id for any menu etc, there would be problems. Be good if you could request a range of ids from winamp.
neFAST
11th September 2004, 15:29
thanx for the bug fix :)
I still hav some dumb question, here's my code :Const ForReading = 1, ForWriting = 2, ForAppending = 8
Set fso = CreateObject("Scripting.FileSystemObject")
Set MyFile = fso.OpenTextFile("C:\Program Files\Easyphp\www\songs_temp.txt", ForWriting, True)
mlq = medialibrary.runqueryarray("type = 0")
for each track in mlq
if track.ATFString("%year%") < 0 Then
MyFile.WriteLine(track.artist + ";" + track.album + track.ATFString(";%tracknumber% ") + track.title + track.ATFString(";%bitrate%;%lengthf%;;%genre%"))
Else
MyFile.WriteLine(track.artist + ";" + track.album + track.ATFString(";%tracknumber% ") + track.title + track.ATFString(";%bitrate%;%lengthf%;%year%;%genre%"))
End if
next
MyFile.Close()
set cmd1 = CreateObject("Wscript.Shell")
cmd1.Run "sort C:\Progra~1\Easyphp\www\songs_~1.txt /o C:\Progra~1\Easyphp\www\songs.txt"
quit
Id like to add set cmd2 = CreateObject("Wscript.Shell")
cmd2.Run "del C:\Progra~1\Easyphp\www\songs_~1.txt"
or cmd1.Run "del C:\Progra~1\Easyphp\www\songs_~1.txt"
but both don't work :(
any clue ?
And I have a totally OT question, a friend would like a random question that first choose a random artist and then one of his songs. He doesn't want to ear too much an artist when he owns his whole discography, you see ?
Do you think I could do this with your plugin ? I think I need to query the ml with a DISTINCT option and the randomize on the artist. Then i just have to re-query with that artist and re-randomize one song.
THe problem concerns that "distinct" (like in SQL), I think it's not possible to query the ml like that, is it ?
electricmime
11th September 2004, 17:20
i think i have the script like i want it, though... i have yet to figure out how to get it to play the first track of the cd.. but thats not that big of a deal
my question is.. how can i add it to the script to sort the album by track number.. because sometimes when i 'insert album' some albums list the album backwards.(from last track to first)
thanks
DrO
11th September 2004, 17:24
Originally posted by shaneh
But there is stil the problem of command ids being used by other plugins. AFAIK the current standard is just use any old random spare id when adding to menus etc. If any two plugins try use the same id for any menu etc, there would be problems. Be good if you could request a range of ids from winamp. there's a lot Winamp should do like natively handling menu insertion, etc but i doubt anything like this will happen (i've asked about a few things and basically have been told no)
Originally posted by AnodA
... get alphas to 1.x state for exampleyup and some other things that are posted around. anyway back to the thread topic plzkthx
-daz
shaneh
12th September 2004, 00:02
@NeFast, I found this example in the msdn docs, it should work ok:
Dim fso, MyFile
Set fso = CreateObject("Scripting.FileSystemObject")
Set MyFile = fso.CreateTextFile("c:\testfile.txt", True)
MyFile.WriteLine("This is a test.")
MyFile.Close
Set MyFile = fso.GetFile("c:\testfile.txt")
MyFile.Delete
As far as I know there is no 'distinct' option, but there are many ways to overcome this. Just query for every song, then add each to a 'scripting.dictionary' object, using the artist as the key, and maybe the number of songs by that artist as the value, or anything else it doesnt really matter, it wont allow you to add duplicate keys. Then just choose a random one from 1 to .count.
I want to avoid writing scripts for everyone though, and concentrate on the plugin which allows such scripts to be written. Unless I find that the script requires some change to the plugin.
@electricmime: You will need to sort the results after you get them. Its not too difficult, I'll post up a script that does it soon.
shaneh
12th September 2004, 05:56
+Fixed more problems with ATFString when stuff wasnt loaded from the media library.
+Added basic support for sendto_*.vbs items. You can get the items through GetSendToItems().
+It will not start scripts or register hot keys etc until all plugins have finished initing.
Fixed some example scripts that wouldnt quit properly if not enough items were selected. Added a send to 'export sorted' example.
The basic API is getting pretty close to complete. Theres still a few things here and there, but the most used things are there.
I still need to add methods for adding menu items and hot key callbacks etc. Plus some gui stuff as well as loading .js and other script types.
AnodA
12th September 2004, 08:37
...back to the thread topic - yeah, that's what it's meant to be! Don't want to keep shaneh off form doing his plug. But ideas rise.
@shaneh:
1. That config thing you planed would be great I think. Keep this in mind, please! The scripts that are loaded or displayed should be set in an easy way. Not like it's actually with the Winamp plugins - I can't stand copy or deleate files in a folder somehow getting confused about my lastest setting, what plugs I need to do what I want, which combination of things can cause problems or where (damn) is the plug I tried out some time before (and that's EXACLTY what I need now!!) - I just want to define: Load or display this script or ignore this script till I tell you not to do this. Something special would be to have a couple of presets to choose - but I only want to be inquired if I really want to be. It should be easy to config for people that know not much about computers (should be the main aim ever, everybody knows). Too much? Doesn't mind. I just want to tell you: Take your time, finish the functionality first and think about the best way integrating this into Winamp. It's a promising thing I'm sure about that. Though it might grow to work more than fun ;) . It's people like you bringing fun to other people. But you see the problem many scripts installed?
(btw s.o. agree that's nice for the plugin issue... no, sorry, getting of topic again. Perhaps that's something for the discussion forum)
2. Dreamed about OnWinampClosedown issues. Could be great if someone wants to fix things (last playlist, statistics, whatever...). Could be done with some watch things I know but would be better to do this in a clean and simple way. Agree?
3. The example scripts are fine right now. It's the best way to follow what it's intended to do. Please keep on including them.
Hope I'm not a pain in your neck - keep quiet now till there's something important.
Happy coding...
neFAST
12th September 2004, 12:12
Hello I've done the "clever random" plugin I was talking about.
dim i,j,Dict1,keys,tracks
i = 0
x = playlist.getselection()
Set Dict1 = CreateObject("Scripting.dictionary")
Dict1.CompareMode = BinaryCompare
mlq = medialibrary.runqueryarray("type = 0 AND trackno = 1")
for each track in mlq
Dict1(track.artist)=i
i=i+1
next
Randomize
keys = Dict1.keys
do while (tracks<=10)
Rand = Int((Dict1.Count + 1) * Rnd)
mlq2 = medialibrary.runqueryarray("artist HAS """ + keys(Rand) + """")
j=0
for each track in mlq2
j=j+1
next
Rand2 = Int((j + 1) * Rnd)
mlq2(Rand2).insert(x(1).position)
tracks=tracks+1
Loop
quit
It was a bit slow so I added "trackno = 1") in the first query so that each album is called one time. The drawback is that this will totally mess up the random if you don't have your tags correctly filled !
I repeat that I'm a total newbie with VB so If you see any way to optimize this plugin, please tell me.
And now "dumb question session" :)
Is it possible to add an item in the playlist when it's empty ? shaneh uses "if ubound(x,1) > 0 then" to avoid adding anything in that case, so I don't kwow ....
Then is it possible to put a form in a msgbox to asks the user for the number of files he'd like to add ?
neFAST - not that fast :)
shaneh
12th September 2004, 12:28
ubound(x) just checks the number of values in 'x'. x is an array obtained from 'playlist.getselection'. So it effectively checks the number of values selected.
If the playlist is empty, then obviously the selection will be empty too. But you still need a place to insert. Thus you will have to manually choose a location, or you can use playlist.position. You can use playlist.count to get the number of items in the playlist.
If you dont care about the position and just want to enqueue it to the end, you can use track.enqueue.
Note in your example, you would be better off doing
j = ubound(mlq)
rather than a loop to find the number of items in the second query. That part wouldnt be too slow though, it would be adding the items to the dict object that would be slow. Im not sure of a faster way though. You could try doing 'ifexists(key)' or whatever and not re-adding a value if it does and see if its faster, i dont think it would be though.
The gnu sort utility allows you to list all the unique items using
sort -u file.txt
So you could try writing all the artists to a file then running that utility over it and see if its any faster. Then using wc to count the number of lines then read a random line etc. I am not sure if it would be ultimately faster though. But the advantage is you can cache the results in the file and not have to re-generate the list everytime.
You can do:
num = CInt(InputBox("number of items"))
to get a value from the user.
shaneh
12th September 2004, 13:03
Adding on this rather than editing:
It seems the slow part is having to do a query for every track you want to add. Queries are qutie slow
It may be possible to speed up your script by having the 'value' part of the key/value pair be a list of the available songs. ie, lookup the artist in the dictionary, then modify the value to include the database index of the new item.
You can obtain the dbindex from the media item through 'track.dbindex'. Or use the index into the array.
So basically your dictionary (key,value) would look like:
"Metallica", "10:16:17:20"
"Spearhead", "23:34:234:1:235:92"
---------------heres a script that will do it---------
dim i,j,Dict1,tracks,num,idxs
Set Dict1 = CreateObject("Scripting.dictionary")
Dict1.CompareMode = BinaryCompare
mlq = medialibrary.runqueryarray("type = 0")
i = 0
for each track in mlq
Dict1(track.artist)=Dict1(track.artist) + ":" + CStr(i)
i = i + 1
next
Randomize
itms = Dict1.Items
num = CInt(InputBox("Number of items"))
do while (tracks<=num)
Rand = Int((Dict1.Count + 1) * Rnd)
idxs = Split(itms(Rand), ":", -1, 1)
Rand2 = CInt(idxs(Int(ubound(idxs)+1 * Rnd)))
mlq(Rand2).enqueue
tracks=tracks+1
Loop
quit
neFAST
12th September 2004, 15:38
Shaneh : you said you wanted to avoid scripting for everyone :(
now you've made a faster and clearer script in 20min, do do you want to discourage me ? :p
well, hum, thank you !
[edit]
I must tell you that your Export sorted script is not very fast and useful,:-þ maybe an "album list" would be more interesting, using dictionary to list only unique data
shaneh
12th September 2004, 22:26
It is not useful, but it does show how to use the 'send to' feature, and how to sort an array after a library query, based on a string field. And that is its only aim.
saivert
15th September 2004, 13:32
You can't add your hotkey actions to Global Hotkeys plugin in the init() function. I have a solution for this which is attached. It uses a timer...
shaneh
15th September 2004, 13:38
Timers are unreliable, it is dependant on the speed of the machine. It also means you miss any inital messages if you dont init everything until the timer fires.
It is much easier to just postmessage a custom message to the winamp hwnd. You will not get the message until all the plugins have been init'd. You will get it as soon as the plugins have all been loaded and init'd, and winamp is ready to start doing stuff.
alternatively, you can make the hot key registration a postmessage itself.
CaAl
17th September 2004, 14:07
Wow! great plugin. It helped me answer this problem:
[chronological overview of songs] (http://forums.winamp.com/showthread.php?s=&postid=1473373#post1473373)
For those interested, I used this script:
Dim x, s, sy, ey, y, wd
Set wd = CreateObject("InternetExplorer.Application")
wd.Navigate2("about :blank")
wd.document.write "<html><head>"
wd.document.write "<title>Winamp Chronological Report</title>"
wd.document.write "</head>"
wd.document.write "<body bgcolor=black text=#CEFFCE>"
wd.document.write "<p><table border=1 cellpadding=0 cellspacing=0>"
sy = 1949 'start year
ey = 2004 'end year
mlq = medialibrary.runqueryarray("YEAR > 1 AND YEAR < " & sy)
x = 0
For Each track In mlq
x = x + 1
Next
wd.document.write "<tr><td>before "& sy & "</td><td align=right>" & vbNewLine
wd.document.write x & "</td></tr>" & vbNewLine
For y = sy To ey
mlq = medialibrary.runqueryarray("YEAR = " & y)
x = 0
For Each track In mlq
x = x + 1
Next
wd.document.write "<tr><td>" & y & "</td><td align=right>" & vbNewLine
wd.document.write x & "</td></tr>" & vbNewLine
Next
mlq = medialibrary.runqueryarray("YEAR < 1")
x = 0
For Each track In mlq
x = x + 1
Next
wd.document.write "<tr><td>no year</td><td align=right>" & vbNewLine
wd.document.write x & "</td></tr></table>" & vbNewLine
wd.document.write "</body></html>"
wd.visible = True
(I based it on earlier mentioned scripts as you can see)
shaneh
18th September 2004, 14:37
Have made a couple modifications to allow external scripting (ie standalone WSH scripts and VB apps etc).
It will only work if Winamp has already started, otherwise it annoyingly tries to download the component because it thinks it doesnt exist. You can just run winamp.exe to ensure it is loaded before trying to access it.
I can fix this by registering it in the registry, but will try work out something different. Its probably a bit buggy, but seems to work for the most part. Have also added a simple volume property and track property to media items, plus a couple other example scripts.
Set wo = GetObject("clsid:1C7F39AF-65C0-4C14-A392-6B4714705DC2")
wo.play
shaneh
21st September 2004, 06:00
Fixed class registration, also registers in the registry. You can now access it properly from external scripts and apps etc.
---
Set wo = CreateObject("ActiveWinamp.Application")
wo.play
---
Added a dialog to see running scripts and let you kill them off. Good to see if any scripts havent quit properly. You can also run arbitrary scripts from this dialog. Accessed from the config screen for the plugin under general plugins, preferences. I will enhance this dialog and make it more accessible over time.
Other misc fixes.
saivert
21st September 2004, 06:34
Heres a script that gives you easy access to the scripts folder.
It will work on all systems without modification because it uses the registry to find out where Winamp is kept on your computer.
' Opens the script folder
' Written by Saivert
Const StrRegKey = "HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall\Winamp\UninstallString"
Dim WshShell, path
Set WshShell = CreateObject("WScript.Shell")
path = Application.GetIniDirectory & "\plugins\scripts"
WshShell.Run path
quit
Also a script that launches Winamp and makes it play at startup (external).
' Launches Winamp and makes it play
' Written by Saivert
' The following constant must be on one line:
Const StrRegKey = "HKLM\Software\Microsoft\Windows\
CurrentVersion\Uninstall\Winamp\UninstallString"
Dim fso, WshShell, path
Set fso = CreateObject("Scripting.FileSystemObject")
Set WshShell = CreateObject("WScript.Shell")
' Detect path to Winamp using registry
path = fso.GetParentFolderName( WshShell.RegRead(StrRegKey) )
WshShell.Run path + "\winamp.exe"
Set wo = CreateObject("ActiveWinamp.Application")
wo.play
Good work ShaneH!!!
shaneh
21st September 2004, 07:40
+Tweaked the registration a bit more, the type library is now registered which means .cpp clients will actually work.
Ive used the wrong type for a lot of stuff (VARIANT), I thought this was best for scripts, but I think it doesnt matter. Making them types like LONG/BSTR/INT etc will make writing CPP clients much easier, especially with later versions of VS. So I will probably convert a lot of stuff, it makes it easier to see what types the functions return and take easier too.
shaneh
21st September 2004, 07:43
A simple example in MFC/Cpp which uses the component. Be careful about writing anything significant at this point in time, as functions and library names etc are expected to change.
saivert
21st September 2004, 08:12
How do you get the so called "script helper" loaded as a Media Library plugin? gen_script1.dll does not export winampGetMediaLibraryPlugin.
shaneh
21st September 2004, 09:14
There are IPCs to add and remove media library plugins. An ML helper plugin was necessary in order to get the 'send to' items.
saivert
21st September 2004, 13:08
You mean through this:
These are reverse engineered, so may not be supported
too well or entirely accurate.
long libhwndipc = (LONG)SendMessage(hwndWinamp,
WM_WA_IPC, (WPARAM)"LibraryGetWnd",
IPC_REGISTER_WINAMP_IPCMESSAGE);
And then using the standard ML_IPC_* like:
/* pass a winampMediaLibraryPlugin *.
Will not call plugin's init() func.
YOU MUST set winampMediaLibraryPlugin->hDllInstance to NULL,
and version to MLHDR_VER
*
#define ML_IPC_ADD_PLUGIN 0x0750
#define ML_IPC_REMOVE_PLUGIN 0x0751 /* winampMediaLibraryPlugin *
of plugin to remove. Will not call plugin's quit() func */
shaneh
21st September 2004, 13:14
Yep
saivert
21st September 2004, 13:42
That's very assuring!! Now I can finally get on the train home (I'm sitting at school). Bye, will be back tomorrow...
shaneh
22nd September 2004, 06:57
what a waste of time :P
It reminds me of a plugin I intended to write a while back but never did. One of these days I will... Should be pretty good if it works out. Will see how I go for time.
---------
Const ForReading = 1
Set fso = CreateObject("Scripting.FileSystemObject")
Set MyFile = fso.OpenTextFile("C:\art.txt", ForReading, True)
Do While MyFile.AtEndOfStream = False
artline = MyFile.ReadLine
if artline = "" then
artline = " "
end if
set sep = LoadItem("x:" + artline + ".x")
sep.Enqueue
Loop
MyFile.Close
quit
saivert
22nd September 2004, 09:20
Oh what a cute little teddy...
Maybe you could write a quote of the day script too, that will randomly drop lines from a quote file and scatter it around in the playlist. Would be very similar to the teddy script.
electricmime
22nd September 2004, 10:04
in the atfe thread, i thought it would be cool if you could save atf strings, and change them whenever you want(from the playlist window) would that be possible through scripts(and if it is, would it be possible to update all the files once you change atf strings)
FarmerDave
22nd September 2004, 11:56
shaneh - excellent work - I was casting about for a way for controlling winamp on my server - didn't like any of the existing stuff out there, so started writing my own using .net remoting - this has saved me a *ton* of effort, thanks!
One request, or maybe I'm just missing it - can you add a "current playback status" property (i.e., Stopped, Paused, Playing)?
Thanks again,
FarmerDave
neFAST
22nd September 2004, 21:27
I'm still a little off-topic but I just want to say that the rand Items plugin always insert the 2nd song of an album !
I don't really understand the last line of the code (CInt(idxs(Int(ubound(idxs)+1 * Rnd)))):Rand = Int((Dict1.Count + 1) * Rnd)
idxs = Split(itms(Rand), ":", -1, 1)
Rand2 = CInt(idxs(Int(ubound(idxs)+1 * Rnd)))
mlq(Rand2).enqueue
But I think the problem is here.
any idea ?
[edit]
me and my beloved brain have found the answer :
I juste changed the brackets and +1 in the random
Rand = Int(Dict1.Count*Rnd+1)
idxs = Split(itms(Rand), ":")
Rand2 = Int(idxs(Int(ubound(idxs)*Rnd+1)))
mlq(Rand2).enqueue
shaneh
23rd September 2004, 09:12
Plenty of changes. The library is now named ActiveWinamp instead of gen_script1Lib.
+ Many of the methods now return strong types rather than variants. Changed types used internally and externally quite a bit, should work better.
+ Fixed a serious problem with closing scripts.
Application:
+SendMsg() - does a sendmessage to the main hwnd
+PostMsg() - does a postmessage to the main hwnd
+UpdateTitle()
+RunScript(BSTR)
+Property PlayState
+Property Hwnd
+Property Panning
-Events:
+ChangedVolume()
+ChangedStatus()
+PlaybackEOF()
Playlist:
+SendMsg()
+PostMsg()
+Property Hwnd
MediaLibrary:
+SendMsg()
+PostMsg()
+Property Hwnd
You can use the sendmsg and postmsg methods to do many of the other actions not available natively to the plugin.
shaneh
23rd September 2004, 09:19
Much more interesting sample in MFC, demonstrates how to do ml queries and work with the arrays. The previous example wont work anymore due to the changes in gen_script1.
saivert
23rd September 2004, 09:45
I'm now also using a "helper ML plugin" in my plugin NxS Balloon Tip (http://www.winamp.com/plugins/details.php?id=138431
). And I also get the data from the Media Library instead of using IPC_GET_EXTENDED_FILE_INFO.
ON-TOPIC
I'm writing documentation for your plugin, that means all the methods functions described and a couple of guidelines. Hope you'll like it...
shaneh
23rd September 2004, 09:49
Sounds good saivert. I will eventually get around to writing up the .idl file properly, so that when using it within VB or othewise using the type library, there will be some better help contexts for the methods/properties.
If you want you can fill in this idl file, or just use it as a reference.
saivert
23rd September 2004, 10:20
I actually didn't need the .idl file as I can use OLEView (bundled with VC++) to de-compile the .tlb file into a .idl file again. I will not fill in the idl file however becuase I am writing documentation for use by anyone, and not just people who can read idl file like it was a novel.
It will be more structured and have a tree-like form with examples along the way.
Here is the first draft:
shaneh
23rd September 2004, 10:53
Ok looks good saivert.
Although there is still heaps to do with this plugin, its nearing a point where I am happy to release it and the names and dispids etc will all remain fixed. I need to add plenty of stuff for dynamically adding hotkeys/ menu /items /arguments to scripts etc. But that is mostly for script hosting stuff and can be added over time without affecting the rest of the functionality.
Ive been holding off doing any docos etc until I set the interfaces in stone. But it currently provides most of the typical stuff you would use from an external program through COM, so I may release it.
The reason for editing the .idl file is not for people to read that, but it is used to compile the type library. The help strings are part of this library, in this way the object is self documenting. When using it in VB or any other environment, the help strings that are put in this .idl file appear in the object browser. A good IDE will also provide little tool tip texts with these help strings when using a method from the type library.
(the position property in the playlist is both set/get).
shaneh
23rd September 2004, 15:43
Fixed a leak problem with arrays (runqueryarray/getselected/getsendtoitems).
Fixed issue with getting meta data from items not in the ml.
Fixed sample client app
shaneh
23rd September 2004, 15:44
The mfc sample app. Works much better.
saivert
24th September 2004, 09:31
All done!
I hope it will be included in future releases of ActiveWinamp.
Note: The ZIP also contains two scripts i have written, check em' out ;)
Here it is:
John Baker
28th September 2004, 15:29
Can a script be used to randomize a playlist?
electricmime
28th September 2004, 18:18
theres already one for randomize selection included, and if you want to randomize the entire thing in winmap click misc->sort->randomize list
but if you really wanted to make the script, you could just edit randomize selection
John Baker
28th September 2004, 21:03
I'd like to automate it so that it can be scheduled to load a playlist and randomize it. Currently, I am simply scheduling it as a task. If I could run a script instead of a playlist that would randomize after load that would be ideal.
shaneh
30th September 2004, 13:03
Scripts now run in a separate thread. This allows you to to lengthy operations such as connect to remote web sites or databases etc without locking up winamp. Note that lengthy operations within the Application object itself (basically all exposed methods) will still lockup winamp due to the way it is implemented. (in particular ml queries which take a long time). But when the script isn't 'inside' an exposed method winamp will still be responsive. (ie when calling methods on other objects or other execution which doesnt spend time in calls to the exposed methods).
Also fixes some mem leak issues with ml queries.
The quit method now quits when you call quit rather than just signalling that it should quit when the script is finished. Note there may be some occasions where it doesnt quit immediately and may continue executing for a couple more lines, so structure your code accordingly until its fixed.
Theres likely to be a few bugs but it seems to run ok so far.
@John Baker: That would probably require an event which fires on opening of new items. No such event exists yet.
You can however use this script:
SendMsg 273, 40029, 0
playlist.postmsg 273, 40212, 0
quit
And assign it a hotkey or something. Then use this to open playlists. It sends the 'open file dialog' command to winamp, then the 'randomize playlist' to the playlist after the dialog is closed.
FarmerDave
30th September 2004, 13:43
shaneh - thanks again for this plugin, my remote is working great. I've still got a bunch of stuff to do - software is never truly "done", eh?
Anyway, I turned a friend onto your plugin, and he's asking if there's a way to get to the album art (even just a filename) using this OM. I didn't see one, so I'm passing the question along. If not, do you have any plans to expose such a property/method?
Thanks,
FarmerDave
shaneh
1st October 2004, 00:50
@Farmerdave: You can just use
mi = playlist(1)
fn = mi.ATFString("%dir%") + "\Folder.jpg"
Or various other combinations. I personnaly use a script like:
x = playlist.getselection()
if ubound(x,1) > 0 then
set wso = CreateObject("Wscript.Shell")
pos = InStr(8, x(1).filename, "\", 1)
mpath = Left(x(1).filename, pos)
mpath = Mid(mpath, 8)
wso.run "C:\Mp3\downart """ & mpath & """"
end if
quit
In order to download mmissing albumart using a tool which connects to the web and downloads cover images. downart is a batch file which changes directories and calls mp3albumartdownloader etc.
If you are talking about getting the cover art out of the id3 tag, I think id3lib comes as a COM library as well. You would need to do something like:
id3o = CreateObject("ID3Lib.Application")
id3o.loadtag mi.filename
pic = id3o.getcover
or whatever. I may put id3 support in this plugin, but I think external support may be a better option.
edit: see http://forums.winamp.com/showthread.php?postid=1485468#post1485468
for an example of using id3com to access id3 tags.
shaneh
2nd October 2004, 02:17
To demonstrate a lengthy web service type script and the multi-threading support, heres a neat little script. It will query Audioscrobbler for the top songs by a song selected in your playlist and attempt to enqueue them.
Prob got a few bugs, but you get the idea.
-------playlist_enqueue artists top songs as.vbs---------
dim xmlhttp, art, dict1, mlq
x = playlist.getselection
if ubound(x) > 0 then
Set Dict1 = CreateObject("Scripting.dictionary")
Dict1.CompareMode = 1
art = x(1).artist
mlq = medialibrary.runqueryarray("artist = """ & art & """")
i = 1
for each song in mlq
dict1(song.title) = i
i = i + 1
next
set xmlhttp = CreateObject("Msxml2.XMLHTTP.4.0")
set xmlDoc = CreateObject("Msxml2.DOMDocument.4.0")
xmlhttp.Open "GET", "http://www.audioscrobbler.com/music/" + art, false
xmlhttp.Send
res = xmlhttp.responsetext
xmldoc.validateonparse = false
xmldoc.resolveexternals = false
ns = "xmlns:asx='http://www.w3.org/1999/xhtml'"
xmldoc.setProperty "SelectionNamespaces", ns
xmldoc.loadxml replace(res, "&", " ")
If (xmlDoc.parseError.errorCode <> 0) Then
Dim myErr
Set myErr = xmlDoc.parseError
MsgBox(myerr.reason + " " + myErr.srctext)
quit
end if
set nl = xmldoc.documentelement.selectSingleNode("asx:body/asx:div[@id='main']/asx:div[@class='content']/asx:table[@class='topn']")
set tl = nl.selectNodes("asx:tr")
for each song in tl
idx = dict1(song.selectSingleNode("asx:td/asx:a").text)
if (idx > 0) then
mlq(idx).enqueue
end if
next
end if
quit
shaneh
3rd October 2004, 05:41
+ Hopefully fixed a couple problems introduced by threading
+ Scripts with certain types of errors quit properly now
+ The Quit function should work ok without race problems
+ Added a 'position' property to get the current track position
+ A couple example scripts
electricmime
3rd October 2004, 06:57
so.. is it possible to make a script that changes your atf string?
shaneh
3rd October 2004, 07:46
I guess you could write a script which reads in winamp.ini and modifies the ATF setting in there, winamp supports no other means of changing this setting. You may need to restart winamp to get this setting to stick, Im not sure. Then you would need to re-read in all the titles for the new setting to reflect in the playlist, this can be done by a 'select all, read extended info' button emulation bit of script, but it would be slow for a lot of items.
Its not something that you can just quickly switch between different settings. Frankly I dont think its too practical.
shaneh
4th October 2004, 23:58
Added Arguments and Description(rw) properties to SiteManager.
Description allows you to set/get the text used in the running scripts dialog.
Arguments allows you to obtain the arguments passed by 'RunScript', which now takes an 'arguments' paramater.
The running scripts dialog lets you pass arguments to opened scripts.
Allows you to run scripts from the playlist through 'script:\' items. You can also pass arguments, check out the pause and closewinamp examples to see what I mean.
(scripts run in this manner will get a "-pos=x" argument indicating the position in the playlist it was run from. You should use this instead of playlist.position because it is threaded and may have changed by the time you read it in).
Un-done some thread fixes which werent needed.
Fixed 'Quit' a bit more, plus some problems with scripts with errors not quitting properly.
A few more example scripts.
shaneh
9th October 2004, 00:46
+Fixed a problem with getting events from the object in web pages. The net effect is you can now receive events properly in HTML pages. This is demonstrated in a simple notify.hta application. (note that this plugin is not marked safe for scripting, so you cannot just run this from random internet web pages for security reasons).
+Fixed a crash problem with getting meta data from files which arent in the media library.
DAVOR
10th October 2004, 11:00
(sorry about my english)
Shaneh,
the "gen_script1.*" and other files are in my winamp5 dir.
Scripts ar there too. How do I start a script. When I Dbl_Click a script it return me an error. See the picture. It happens on each script.
How do I start it????:cry:
shaneh
10th October 2004, 11:03
I suspect you do not have the media library installed and loaded? Make sure you do, and configure it to load at winamp start.
If you do not wish to use this, the other scripts which dont use the media library may work, but Im not sure. Its best just to enable the library, Hope it works out ok.
EDIT: oh, you are trying to run the scripts through windows... run them from winamp via the 'scripts' right click menu item in the playlist.
You can write scripts that run externally, but most of the scripts included were not written like this.
Just adding :
set wa = CreateObject("ActiveWinamp.Application")
and "wa" in front of all the method calls and properties, and remove the 'quit' call and the scripts should work ok externally.
DAVOR
10th October 2004, 11:13
Winamp 5.04 with media l. is loaded I Dbl click any of scripts, the error is still there.
shaneh
10th October 2004, 11:24
As stated above, those scripts are not designed to be run externally, although it is possible.
If you are planning on using this to extract the selected files from an external app, I would advise importing 'ActiveWinamp.Application' and calling methods on it directly, namely playlist.getselected(), which returns an array of mediaitems. There is a cpp example in this thread, but it can be adapted to VB easy enough.
CaAl
15th October 2004, 13:58
Is there a way to work with a rating-system that support more levels than the standard-ID3V2 5-star system? (Preferably, ratings between 1 and 100).
I'd like it to be possible to set these ratings in Winamp - not some external program - and, if possible, also save this info in the ID3 tag.
I've tried some things, but it seems that Winamp deletes custom ID3V2 tags when you change e.g. the title of a song - which is obviously annoying.
Anyone?
shaneh
15th October 2004, 15:36
The standard id3v2 system is actually 0-255. Winamp uses a 5 star system in its ML. I dont believe I set a limit in this plugin, so you should be able to set the rating to whatever you like. Dont expect it to be displayed in the ML of course, it uses ***** and theres nothing you can do about that.
If you take a look at the ID3 rating export/import script I wrote, you could modify it to write whatever rating number you like to the field. I currently just take the rating and multiply/divide it by 51 in that script which is what WMP does. But again, the ML will ignore whatever you write to this tag, the ML does not read in rating data from id3 tags by default.
CaAl
18th October 2004, 09:48
Thanks for the answer. Another question:
Is it possible to turn some kind of function on/off? I want a script that executes some actions each time a song is played, but only when I am in "perform this on each song-mode". When I'm not in that mode, it should do nothing. How can I do that?
CaAl
18th October 2004, 11:21
Is it also possible to have some script to be executed every X minutes? (Just like the media library is re-read every Y minutes)
shaneh
18th October 2004, 12:56
You can write a startup script that does the following:
settimeout 50000, getref("myfunc")
sub myfunc
settimeout 50000, getref("myfunc")
msgbox "interval"
'possibly quit on some condition
end sub
As for the on/off functionality. You can open the configuration dialog and click 'run script' to run a script. When you want to turn it off, click the running script in this dialog.
Its not the best interface for achieving this, but it should work ok. I'll work on making a tick mark against a menu item type interface later on.
CaAl
20th October 2004, 10:43
A while back, MTV Europe had a show called Three From One. They played three songs in a row from the same artist.
I've written a script that automatically enqueues a song each time a new song is played, in such a way that you'll get three songs in a row from a random artist, followed by three in a row from another random artist. (If the artist doesn't have three songs in you media library, it will of course play fewer songs). It's attached. Toggling the script on/off can be done via the configurationwindow of Shaneh's plugin.
shaneh
8th November 2004, 01:47
Released as "ActiveWinamp" to the plugins page.
http://www.winamp.com/plugins/details.php?id=143299
Be sure to delete gen_script1.dll from your plugins directory before starting winamp after installing, otherwise you will get problems. You will need to re-register the gen_activewa.dll if you don't.
jsonnabend
8th November 2004, 04:36
I'm trying to use ActiveWinamp in a Delphi program, but I keep getting the error that the IPlaylist class is not registered. Any ideas what may be causing this?
TIA
- Jeff
shaneh
8th November 2004, 06:34
Are you trying to instantiate the playlist object directly or are you obtaining it from the IApplication class?
You must get the ActiveWinamp.Application object, and from that get the playlist object from the "playlist" property.
Havent used delphi before, but you will need to import the gen_ActiveWinamp Type Library too however that is done.
jsonnabend
8th November 2004, 14:33
Shaneh -
Thanks for the input. You were correct about the cause. It looks like I'm good to go, at least until the next issue. ;)
Thanks again.
- Jeff
AnodA
8th November 2004, 22:03
Originally posted by shaneh
Released as "ActiveWinamp" to the plugins page.
http://www.winamp.com/plugins/details.php?id=143299
Can't find this in Plugin Pages :(
DrO
8th November 2004, 22:06
looks like the dodgy download server is back in use :(
the plugin is submitted and was showing the published list, guess you'll have to wait for a different server to come into use (not much that can be done)
-daz
shaneh
9th November 2004, 03:35
You can try:
http://205.188.244.130/plugins/browse.php?category=999&ctype=P
.138 seems to be dodge. Just refreshing a few times should get you the other ip anyway.
jgallen23
10th November 2004, 16:23
I've been looking for a way to mass change the genre of my playlist and I was wondering if this is something that I could do with this plugin. I know a little VB.net, but not enough to get started, could somebody give me a little help to get me started. Thanks
Greg
shaneh
11th November 2004, 00:55
Yeah, just do a query for what you want to change with "runqueryarray" or get it from the currently selected items, or from the send to menu or wherever, then loop through and change each items genre.
A quick example which puts it on the "send to" menu:
---sendto_change genre.vbs----
x = GetSendToItems
newgenre = InputBox("Genre")
for each track in x
track.genre = newgenre
next
quit
--------
Or to change the selection in the playlist.
---playlist_change genre.vbs----
x = playlist.GetSelection
newgenre = InputBox("Genre")
for each track in x
track.genre = newgenre
next
quit
-----------
or to just change the entire playlist
newgenre = InputBox("Genre")
for each track in playlist
track.genre = newgenre
next
quit
jgallen23
11th November 2004, 15:25
Thanks!....now will that write to the ID3v1 tag or ID3v2 tag. I'd prefer it to write to the ID3v2 tag so I can make up my own genres
shaneh
12th November 2004, 02:13
It will write it to the Media library... If you want tag writing you need to get ID3COM. Look at the sendto_export to id3.vbs examples.
Its not too difficult, but if youre not too familiar with it, you may be better off with some kind of mass tagger.
jgallen23
12th November 2004, 16:57
where can I get id3com??
jgallen23
12th November 2004, 17:21
I got id3lib, which is an id3com, is that what I need? Also, once I get that, where do I put the files?
shaneh
13th November 2004, 02:40
You need to put id3com.dll wherever you like, then run
regsvr32 id3com.dll
and you will be able to use it. However, it is a bit tricky to use. As I said, you may be better off with some kind of mass tagger.
billyvnilly
13th November 2004, 04:34
i tried explaining that to him before. i suggested that he use mp3tag (http://www.mp3tag.de/en/) (a mass tagger). You can create a playlist in winamp. save it. open the playlist in mp3tag and mass tag their genres. and it saves it to id3v1 and id3v2.
jgallen23
13th November 2004, 06:03
I have Tag&Rename which works fine, but I want it to be able to do it on the fly without using another program. I think I follow what you did in your script examples, we'll see if I can figure it out ;)
jgallen23
14th November 2004, 19:35
shaneh, where can I find the id3com you used in the script examples?
Thunder Pussy
14th November 2004, 19:59
I realize this plugin (thanks shaneh) is geared toward the do-it-yourself users, but it would be cool if users would post their scripts so those who aren't so adept at writing scripts could make use of the added features, and learn from others' work as well. So far I've dabbled a little (successfully) with simple modifications to existing scripts but when it comes to writing a script whole-cloth I have to admit the included help-file is a little over my head. Earlier in this thread there was quite a bit of posting of scripts, I kinda wish there was more of that.
Regards,
shaneh
15th November 2004, 01:57
http://mysite.wanadoo-members.co.uk/johnadcock/ID3COM.htm
Has a version, not sure how recent though. ID3Com hasnt had an update in a while, its now part of id3lib or something. Not too sure.
An issue with it is it only takes a number for the genre, rather than a string and then converting it. So you will need to do that yourself, unless you can find some other library that uses a string.
http://www.kindel.com/mp3/id3com/default.htm
Seems to take a string, but it didnt seem to work for me if the genre field doesnt exist to begin with. The author of that is putting the code towards id3com so Im not sure which is more recent.
x = GetSendToItems
if ubound(x,1) > 0 Then
set id3co = CreateObject("ID3Com.ID3COMTag")
newgenre = CStr(InputBox("New Genre"))
for each track in x
id3co.link track.filename
if id3co.HasV2Tag then
'set id3 tag (only takes a number)
id3co.Genre = 0
'set media library data
track.genre = newgenre
id3co.SaveV2Tag
end if
id3co.Clear
next
end if
quit
Will work, but note the fact it just sets the genre to '0' (Blues). You will have to work out a way to decide what genre number to use (0-255).
If you can find a command line id3 tagger which takes a filename and a argument, such as:
id3tag "song.mp3" -genre Dance
or whatever, you can use wscript.shell.run to run the command on every item rather than using id3com. There should be an example in this thread by saivert on running an external program.
@¿¢?: Sure I encourage that, I intend to setup a site which will have a repository of scripts, similar to the winamp plugin database. Will take a little while, but in the meantime is there any particular script you are after?
Thunder Pussy
15th November 2004, 03:55
Originally posted by shaneh
@¿¢?: Sure I encourage that, I intend to setup a site which will have a repository of scripts, similar to the winamp plugin database. Will take a little while, but in the meantime is there any particular script you are after?
The one I tried & wasn't successful at was to enqueue the current ml selection after current with a hotkey.
A site for the scripts is a great idea. Maybe I'll catch up by then & can add some to the database. :-)
shaneh
15th November 2004, 04:47
You cant do that actually. The current ml selection is known when the item is selected on the 'send to' menu. Unfortuantly this is a limitation of winamp, there is no documented way to get the selection in the media library other than by selecting an item on the 'send to' menu.
Thus, the command is 'getsendtoitems' as it is the items 'collected' by the Send To menu. And getselected() is a method of the playlist, thus gets selected items in the playlist.
I will take a look and see if there is a practical way to get the selected items in the media library, but it wont appear in activewinamp until the next revision if so.
jgallen23
15th November 2004, 16:33
shaneh, for id3v1 the genre is stored as a number, but for id3v2, the genre is whatever you name it. That's why I just want to change id3v2, it looks like you are saving the v2 tag, but that's odd that it still stores it as a number
Lion12
15th November 2004, 19:09
Hi out there!
I've running two instances of winamp classed as 'Instance1' and 'Instance2'. Using only the library of one instance I have to send items through the 'sendto', right?
I tried something like this:
'sendto_Instance1.vbs
Dim x, WshShell
Set WshShell=CreateObject("WScript.Shell")
x = GetSendToItems
if ubound(x,1) > 0 then
for each track in x
WshShell.Run "c:\\programs\\winamp\\winamp.exe /CLASS""Instance1"" /ADD """ & track.filename & """"
next
end if
quit
(just the same with 'sendto_Instance2')
Seems not to work correctly but I can't figure out the reason.
Right way to do this, or is there a (better) internal way?
Or is it better to have two diffrent winamp installation folders?
regs
Thunder Pussy
16th November 2004, 20:49
Hello, I'm doing some more experimenting and have a question: How do we randomize the results of an insert script? What I've done so far is modify the insert all from album script to make it insert all from genre.
x = playlist.getselection()
if ubound(x,1) > 0 then
mlq = medialibrary.runqueryarray("genre HAS """ + x(1).genre + """")
for each track in mlq
if strcomp(track.filename, x(1).filename) <> 0 then
track.insert(x(1).position)
end if
next
end if
quit
Thank you for your help and patience with me, shaneh. I am just beginning to learn this language. Best regards,
/edit Firefox crashed when I tried to post the formatted text so I had to post it as plain text.
shaneh
17th November 2004, 04:11
What you are trying to do is a pretty common CS problem- randomizing an array. There are various ways to do it, but a simple way with just a small array is to loop through the array swapping each item with a random other item.
Randomize
x = playlist.getselection()
if ubound(x,1) > 0 then
mlq = medialibrary.runqueryarray("genre HAS """ + x(1).genre + """")
i = 0
for each track in mlq
i = i + 1
swapitems mlq(i), mlq(Int((ubound(mlq,1)) * Rnd + 1))
next
for each track in mlq
if strcomp(track.filename, x(1).filename) <> 0 then
track.insert(x(1).position)
end if
next
end if
quit
sub swapitems(ByRef val1, ByRef val2)
set temp = val2
set val2 = val1
set val1 = temp
End Sub
There are a few ways to make this more efficient, for example, there is no real need to loop through the array twice, you can modifiy it to just do it once.
I should have added support for jscript for scripting as well, but didnt have time. Hopefully I will add jscript and maybe perl support in a later release. Adding other language support for the internal scripting is not too difficult fortuantly. VBScript is not too difficult to learn though, and made more sense to use as the default language for now.
shaneh
17th November 2004, 06:38
@Lion12: ActiveWinamp was not really designed with multiple instances in mind. If you popup a msgbox with the track names instead of running winamp.exe does it display the right names? Does the /ADD command work when not using from a script?
Lion12
17th November 2004, 14:59
Jeah, multiple instances with winamp seems to be a really damn thing but many people would like to have two instances running for different reasons... :(
Back to main topic:
1.) the names appear correctly
2.) yes, there seems to be a problem:
the tracks are added to the instance last having focus. So I can't use /CLASS and /ADD at once?
Some weird shell thing:
I start Winwamp with $...\winamp.exe /CLASS"one" and winamp starts.
I type again $...\winamp.exe /CLASS"one" and another winamp opens.
(of coures only if 'allow multiple instances' is checked)
Searched the forums and the old sdk (http://web.archive.org/web/20030621083508/http://www.winamp.com/nsdn/winamp2x/dev/sdk/api.jhtml) but it makes me even more :weird: .
This seems not to be related to your plugin so I will only ask you if it's planed to consider multiple instances or some kind of workaround within your scriptring plugin?
Something like GETWND/TOWND?? :igor: !? Donno that's possible.
Thanx for your attention!
EDIT:
btw: it's no problem to send files to another mediaplayer this way. This helps a little bit by now :up:
maynardkrebs
22nd November 2004, 01:49
Hi Y'all.
I've created an ActiveWinamp script that sends the current track selection to Nero 6 Cover Designer. This is a first pass and could use some error trapping etc, but it works as is. I'm sure the general population would appreciate this so I'd like to find a home for it. Suggestions? Feedback?
BTW Shane, ActiveWinamp rocks!!
' ActiveWinamp Script: "sendto_Nero Cover Designer.vbs"
' Desc: Nero Cover Designer SendTo Script
'########################
' CODE
'########################
Const ForReading = 1, ForWriting = 2, ForAppending = 8
Set wsh = CreateObject("WScript.Shell")
Set fso = CreateObject("Scripting.FileSystemObject")
cdcFile = wsh.ExpandEnvironmentStrings("%TEMP%") & "\watemp.cdc"
Set fcdc = fso.OpenTextFile(cdcFile, ForWriting, True)
sel = GetSendToItems
If ubound(sel) = 0 Then
MsgBox "No tracks selected", vbOKOnly+vbQuestion, "SendTo Nero Cover Designer"
Quit
End If
' Get total selection time
plTime = 0
for each track in sel
plTime= plTime + track.Length
next
' Write collection info
fcdc.WriteLine("[Parameters]")
fcdc.WriteLine("Language=English")
fcdc.WriteLine("[CDINFO]")
fcdc.WriteLine("Type=Audio-CD")
fcdc.WriteLine("Title=Winamp")
fcdc.WriteLine("Artist=Winamp")
fcdc.WriteLine("Tracks=" & ubound(sel))
fcdc.WriteLine("Playtime=" & ConvertSeconds(plTime))
' Write track info
i=1
for each track in sel
fcdc.WriteLine("[Track" & i & "]")
fcdc.WriteLine("Type=Audio")
fcdc.WriteLine("Artist=" & track.Artist)
fcdc.WriteLine("Title=" & track.Title)
fcdc.WriteLine("Playtime=" & ConvertSeconds(track.Length))
i=i+1
next
fcdc.Close
' Launch Nero Cover Designer
ncdPath = wsh.RegRead("HKLM\SOFTWARE\Classes\Nero Cover Designer.Document\shell\open\command\\")
ncdPath = Left(ncdPath, InStr(ncdPath, " /dde"))
wsh.Exec(ncdPath & " " & cdcFile)
Quit
'########################
' FUNCTIONS
'########################
Function ConvertSeconds(lSeconds)
Dim lTmpMinutes
Dim lTmpSeconds
Dim lTmpHours
If lSeconds > 59 Then
'Get's *just* the amount of seconds that will be returned
lTmpSeconds = lSeconds Mod 60
'Do we have more than an hour's worth of seconds?
If lSeconds > 3599 Then
'How many hours are we talking about
lTmpHours = Fix(lSeconds / 3600)
'Take the original seconds and figure out
'how many minutes we have. Then remove from that
'anything that says "60" for the minutes. So we
'don't have "2:60:05"
lTmpMinutes = lSeconds / 60 - (60 * lTmpHours)
'Finally return the value all nicely formatted up
ConvertSeconds = lTmpHours & ":" & _
FormatTime(lTmpMinutes) & ":" & _
FormatTime(lTmpSeconds)
Else
'Ok. We've got something less than an hour.
'How many minutes do we have?
lTmpMinutes = Fix(lSeconds / 60)
'Seconds were already figured above (lSeconds Mod
'60) so we just return the value and we be done.
ConvertSeconds = lTmpMinutes & ":" & _
FormatTime(lTmpSeconds)
End If
Else
'This is for the lazy that sends us less than even a
'*minutes* worth of seconds. Just dress it up and send
'it back.
ConvertSeconds = "0:" & FormatTime(lSeconds)
End If
End Function
Function FormatTime(tval)
If tval < 10 Then
FormatTime = "0" & tval
Else
FormatTime = CStr(tval)
End If
End Function
shaneh
23rd November 2004, 02:23
Cool script, I really should get on making that site with plugins and script etc. After I finish making some updates to Toaster I will look into it.
Though I think .ATFString("%lengthf%") may have saved you some time in formatting the time. I realise the tags are not documented in ActiveWinamp, I probably should have included them in the documentation. They are included in my other plugin, Toaster, though.
Primathon
24th November 2004, 22:24
maynardkrebs, how difficult would it be to write a script that would add the selected song to an open Nero compilation (audio CD or ISO)? That would make burning CDs an absolute snap.
Primathon
maynardkrebs
25th November 2004, 00:21
Originally posted by Primathon
how difficult would it be to write a script that would add the selected song to an open Nero compilation (audio CD or ISO)?
Not sure (yet) ;) Nero does have an object interface that's accessible through scripting, but I've only given it a quick browse. If I come up with something I'll keep you posted.
maynardkrebs
25th November 2004, 01:34
Originally posted by shaneh
Though I think .ATFString("%lengthf%") may have saved you some time in formatting the time.
Hey Shane.
Thanks for the ATFString tip. I found the Toaster doc and that simplified things. My latest incarnation is attached. Notice the hack job using the dict object. I was looking for a way to query the media items selections directly but hit a brick wall.
Some thoughts:
- Having a query method for track selections similar to that for the media lib object would be useful.
- Adding stats support in the query would be useful (#Artists, #Albums/Artist, #Tracks/Album, Total Time etc). That would have eliminated my having to calculate those values using my ugly hack. :D
- Bug or Feature?: when a sendto script is invoked with nothing selected, nothing happens with the script. I added a ubound check to trap this condition (as I've seen you use in your code) but I'm wondering if this is necessary. Does the script just punt if there is nothing selected?
thanx
maynard
' ActiveWinamp Script
' File: sendto_Nero Cover Designer.vbs
' Desc: sendto script to pass the current track selections
' in Winamp to Nero Cover Designer
'
' v1.0 11/24/2004 6:01 PM maynardkrebs
'
'########################
' CODE
'########################
Const ForReading = 1, ForWriting = 2, ForAppending = 8
sel = GetSendToItems
If ubound(sel) = 0 Then
MsgBox "There are no tracks selected in Winamp", _
vbOKOnly+vbExclamation, "SendTo NCD"
Quit
End If
Set wsh = CreateObject("WScript.Shell")
Set fso = CreateObject("Scripting.FileSystemObject")
scdc = wsh.ExpandEnvironmentStrings("%TEMP%") & "\watemp.cdc"
Set fcdc = fso.OpenTextFile(scdc, ForWriting, True)
Set dict = CreateObject("Scripting.Dictionary")
' Total Hack: abusing the dictionary object as a searchable
' data struct for tracking the number of unique artists/albums
' in the current selection and deriving the cd label artist and
' album fields. The logic goes something like this:
' If:Artists Albums Then:LabelArtist LabelTitle
' 1 1 ArtistName AlbumName
' 1 >1 ArtistName Various
' >1 X Various Various
'
tSel = 0
For Each track In sel
key = track.Artist & Track.Album
If Not dict.Exists(key) Then
dict.Add key, track.Artist
End If
' Get the total selection time
tSel = tSel + track.Length
Next
'Assume single artist/single album then verify
cdcArtist = "Artist=" & sel(1).Artist
cdcAlbum = "Title=" & sel(1).Album
bMultArtists = False
If dict.Count > 1 Then
'multiple albums
cdcAlbum = "Title=Various"
artists = dict.Items
dict.RemoveAll
For Each artist In artists
If Not dict.Exists(artist) Then
dict.Add artist, ""
End If
Next
If dict.Count > 1 Then
' multiple artists
bMultArtists = True
cdcArtist = "Artist=Various"
End If
End If
' Write NCD collection info
fcdc.WriteLine("[Parameters]")
fcdc.WriteLine("Language=English")
fcdc.WriteLine("[CDINFO]")
fcdc.WriteLine("Type=Audio-CD")
fcdc.WriteLine(cdcAlbum)
fcdc.WriteLine(cdcArtist)
fcdc.WriteLine("Tracks=" & ubound(sel))
fcdc.WriteLine("Playtime=" & tSel)
' Write NCD track info
i=1
For Each track In sel
' Only include artist name if there are multiple artists
If bMultArtists Then artist = track.Artist Else artist = ""
fcdc.WriteLine("[Track" & i & "]")
fcdc.WriteLine("Type=Audio")
fcdc.WriteLine("Artist=" & artist)
fcdc.WriteLine("Title=" & track.Title)
fcdc.WriteLine(track.ATFString("Playtime=%lengthf%"))
i=i+1
Next
fcdc.Close
' Launch Nero Cover Designer
On Error Resume Next
ncdPath = wsh.RegRead("HKLM\SOFTWARE\Classes\Nero Cover " & _
"Designer.Document\shell\open\command\\")
ncdPath = Left(ncdPath, InStr(ncdPath, " /dde"))
wsh.Exec(ncdPath & " " & scdc)
If E******mber Then
MsgBox "There is a problem starting Nero Cover Designer", _
vbOKOnly+vbExclamation, "SendTo NCD"
End If
On Error GoTo 0
Quit
shaneh
25th November 2004, 11:19
What Ive done with ActiveWinamp is try to map as much as possible that is possible under the Winamp API into a COM interface with a pretty much 1:1 match.
You can do complex queiries on the media library, becase the media library lets you do those queries. The playlist and 'send to' items etc do not give you this possibility because its not possible under the Winamp API. You would have to do it yourself using your own code regardless of whether you are using ActiveWinamp or not. Generally speaking, if somethings complicated to do using ActiveWinamp, you would probably have to jump through similar hoops just using the normal Winamp API. (this doesnt apply to more complicated hooking tricks etc however).
Stats support also isnt supported under Winamp, you would need to do this yourself normally. I wouldnt want to automatically generate these stats, as it would slow it down for when you dont want these stats.
Its possible I could add some support functions which let you pass in an array of media items to generate some stats etc. However the idea of ActiveWinamp is it lets you write the code and do things the way you want them done, without using prewritten stuff. Basically you are making use of the primitive Winamp API, but without having to deal with all the crap and technicalities that usually goes along with writing a plugin.
-sendto: I guess that Winamp doesnt signal the menu item if nothing is selected, so ActiveWinamp wont run the script. The checks are just done for the sake of logic, and perhaps if you try run the script using 'runscript()' or something I guess.
Note Getsendtoitems() returns the collection of items that was last selected when a "script:" menu item was chosen. When running a script from the 'send to' menu, this is obviously the items that are currently selected. However if you call 'GetSendToItems()' at other times, (ie from playlist_* scripts) you will get the last selection.
maynardkrebs
29th November 2004, 03:31
Hey Shane.
Thanks for the previous reply. I understand the limitations you have to work with...
New question. Do you know of another COM library for APE tags similar to ID3COM? I've been using MP3Gain and would like to be able to "see" which files I've tagged as normalized in my library. Right now the only way I'm aware of to do this is to load the files into MP3Gain to get status :(
Thanks
herd
29th November 2004, 18:37
Hello Shaneh,
you have done a great job here.
Thanks to your efforts I could do my "iTunes2winAmp" bridge within 48 hours. Kindly see this:
http://www.aqua-soft.org/board/showthread.php?t=21327
These desktop iTunes remote widgets coded to be using the iTunes COM API can now all be redirected to winAmp.
Not seen on the screenshot is that AndreasV's AveTunes widget would offer an iTunes list of playlists at its context menu and I even could get that redone with the excellent media library bindings!
Really excellent job - I have only two minor issues:
- IApplication:: put_Position() has no effect with WinAmp 5.03.
- IMediaItem::Enqueue is slow if you have to enqueue thousands of items - I miss enqueueing the results of a media library query at a whole: Best would be to return the query as an IPlaylist* and have a IApplication:: putref_Playlist() implemented (just an idea), I could dump the contents into a temp .m3u file and shellexecute winamp on it but even that wouldn't be as seamless as double clicking the playlist in the media lib.
TIA,
herd
shaneh
30th November 2004, 01:39
IApplication::put_Position: Yeah, thats a known issue. For some reason I couldnt find the API to seek in Winamp at the time. It is possible though, I'll add it in a future release. I left the function there so I could add it without breaking the interface, though thats kind of against COM rules... :P. You may use IApplication::SendMsg with IPC_JUMPTOTIME (106) to do it at the moment.
IMediaItem::Enqueue: There is an API to add a returned query to Winamp, however ActiveWinamp converts queries to its own internal "MediaItem" objects. This is done for 2 reasons:
1) The query needs to be freed as it is allocated by winamp.
2) It makes playlist items, items loaded by filename, items not in the ml etc all the same, which makes using AW much nicer.
Which explains why its called 'runqueryarray', as it creates and returns an array of objects.
The "playlist" object doesnt actually keep an array of current items, it queries them from the playlist dynamically. ie, get_Item() actually creates a MediaItem from querying winamps playlist. Thus its not too logical to return a 'playlist' as a result of a query.
I could, and actually did intend, to create another type of query method on the media library, that would return a less flexible query results object. This object would however let you do things like mass updates and send it to winamp etc. I would add a function to convert it to an array of mediaitems also.
Alternatively, I could add a function on the medialibrary that lets you pass in an array of MediaItems, and it converts it to a format suitable for sending to Winamp, ML style. Or just send it to Winamp itself. I would need to see how the ML does it to see if it uses some trick to do it quicker.
I downloaded and read the doc for the fake iTunes proxy thing. You state that ActiveWinamp only supports one client, though it should support as many as you like. What makes you think it only supports one client? It only supports one server/winamp instance, if thats what you meant.
@maynardkrebs: Sorry, Im not aware of such a component. You may be able to find some component which lets you do binary access on a file and query the tag yourself, if its in a easy parsed format. Otherwise, if there is an .exe which lets you do tag operations, its possible to get the output of cmdline programs and work with that..
herd
30th November 2004, 11:07
Originally posted by shaneh
I downloaded and read the doc for the fake iTunes proxy thing. You state that ActiveWinamp only supports one client, though it should support as many as you like. What makes you think it only supports one client? It only supports one server/winamp instance, if thats what you meant.
Sorry I read something somewhere in the code samples and misunderstood that - I'll remove the false assumption. Thanks for the seek thing - worked like a charm.
I found out that dumping 3000 songs to an .m3u and executing winamp on it is slightly faster than enqueueing them in a loop but still not as seamless as from the media library - If you could address the issue in a later release it would be fine but in the meantime I'll gig into the IPC_** vs. WM_COPYDATA stuff. Again, thanks a lot.
herd
2nd December 2004, 11:58
I just found another one:
IMediaItem returns only a partial IP-Address if the current track is a radio stream - there seems to be no possibility to get the streams display name, am I right?
shaneh
2nd December 2004, 12:56
Nope I guess not. If its the current track, you can use tricks with the window title of HWND to get the winamp title. Otherwise you have to do it without the help of AW and use ReadProcessMemory if the program is not running in the same process space as winamp.
I will add a IPlaylist.GetTitleOfIndex() type method. Id rather not just add methods here and there, but add a whole bunch of upgrades and make a new interface, ie. ActiveWinamp.Application.2 etc. That is the proper way to do it in COM, otherwise you never know what methods are supported by the interface.
herd
6th December 2004, 00:23
Adding methods is no problem - removing or altering them is.
Should be no problem if you are still in beta.
Would you mind sharing the source? I could help and e.g. integrate ID3 support into the IMediaItem... I am seasoned with COM but kinda new to WinAmp coding.
shaneh
6th December 2004, 01:23
Adding methods is no problem - removing or altering them is.
Should be no problem if you are still in beta.
Are you sure? I would think youd need to create a new interface so that applications that get your interface have an expected set of APIs to use. ie, if you get the interface x, you can assume that function foo exists. If 'foo' was introduced later, the application would crash trying to call it. It has no way of determining what functions exist other than some kind of version call. To do away with version tracking, you simply try get the interface number as high as you need, and can assume a certain level of functionality on that interface.
Take a look at IContextMenu,2,3, all they've done is add new methods.
Its not really in beta anymore, as it has been released to the plugin site at v1. In these forums was the beta I would say.
However.. I can add those methods and put up a release here until I accumulate enough to warrant another release and make the new functions a new inherited interface.
I will probably release the source to sourceforge at some point, Ive done a couple tricks with COM to get it to work in the unusual environment of a COM server implemented in a extension DLL of an .exe not intended to be one. And it'd be good to get a few people to look it over. But it will require some tidying up first.
You can use id3com to access ID3 tags. Take a look at the sendto_id3 export. example. Finding a copy of ID3com takes a bit digging though. I think its released as part of id3lib in source form. I dont think Id want id3 support in AW, its meant to be an interface to Winamp, and nothing more. Itd be like adding filesystem support to a calculator interface or something. To me, it makes more sense to use external 3rd party libraries to do external 3rd party stuff.
saivert
7th December 2004, 09:13
COM interfaces can be very useful when you have know how to work with them. I don't think people should start learning programming using COM as their first step. Maybe if Winamp itself loaded plugins as COM objects like the Explorer loads Shell Extensions, we would have a much easier life (in programming).
bradroger
11th December 2004, 02:05
I want to create a script that will reduce a song's playcount by 1 if it is skipped in the first 10 seconds or so. Then if your playlist is shuffling along and you skip a song, it doesn't show up as if you've played it. It should be pretty simple but I'm just learning how to do all this so I need a little help. I'm not sure how I can have a script constantly running in the background, without having to loop continuously and bog down the system. Is this possible?
shaneh
11th December 2004, 04:05
I actually had a script that did just that, but Ive since deleted it.
You dont need to loop continuously, I have supplied a 'change song' event that you can respond to. AW will only invoke your method when the song changes.
It would look similar to:
---startup_playcount fix.vbs-----
Dim pos, timerid
timerid = -1
pos = -1
Sub Application_ChangedTrack
if (timerid <> -1) Then
CancelTimer timerid
End if
pos = playlist.position
set mi = playlist(pos)
mi.playcount = mi.playcount - 1
timerid = SetTimeout (10000, GetRef("IncCount"))
End Sub
Sub IncCount
if (playlist.position = pos) Then
set mi = playlist(pos)
mi.playcount = mi.playcount + 1
end if
tiemrid = -1
End Sub
-----------------
Be aware that this will fuck up with songs less than 10 seconds long etc. And probably a few other cases like when the song is not in the ml, has a zero playcount, http streams, you move the song in the playlist during play etc etc. I will probably release a proper plugin that does this a bit more robustly, does calculations based on song length etc if you can wait.
A better script would probably store the filename of the currently playing song then check that after 10 secs rather than the current playlist pos. Or cache the "mi" and check the filename of that vs the currently playing filename on the timer event. Left as an exercise...
Thunder Pussy
16th December 2004, 01:40
Hi, just thought I'd post a script I've been using in case somebody else could use it. This is just a simple modification of the playllist_Rand items script that comes bundled with A/W. It enqueues 100 random songs that haven't been played in the last 7 days.
dim i,j,Dict1,keys,tracks,num,idxs
Set Dict1 = CreateObject("Scripting.dictionary")
Dict1.CompareMode = BinaryCompare
mlq = medialibrary.runqueryarray("type = 0 AND !(lastplay >= [7 days ago])")
i = 0
for each track in mlq
Dict1(track.artist)=Dict1(track.artist) + ":" + CStr(i)
i = i + 1
next
Randomize
itms = Dict1.Items
num = 100
do while (tracks<=num)
Rand = Int(Dict1.Count * Rnd+1)
idxs = Split(itms(Rand), ":", -1, 1)
Rand2 = CInt(idxs(Int(ubound(idxs)+1 * Rnd)))
mlq(Rand2).enqueue
tracks=tracks+1
Loop
quit
Dunno if it's cool to post simple modifications like this but hey maybe somebody can use it. They can change the part that reads "!(lastplay >= [7 days ago]" to read "lastplay issempty" if that's more to their liking.
I guess I'm just posting it to show how I've been using ActiveWinamp, & to show that even somebody who doesn't know how to write code can customize a script to get something that suits their usage.
Have a good one and thanks,
/edit p.s. Shaneh, would you consider adding year as a supported value for future versions of A/W? It would be cool to be able to enqueue or insert random all from year.
shaneh
16th December 2004, 02:10
Ah.. left "Year" out, plus a couple other things. Will put 'em in a future version. Fortuantly most things can be covered with "sendmsg" and 'ATFString' hacks.
To get the year, using mi.atfstring("%year%") should work.
Thunder Pussy
16th December 2004, 02:54
That is where it goes over my head. I am fine with waiting for a future version, should you wish to accomodate it. Year is not very high in my priorities, although it would be neat.
neFAST
25th December 2004, 15:42
Originally posted by CaAl
I've written a script that automatically enqueues a song each time a new song is played, in such a way that you'll get three songs in a row from a random artist, followed by three in a row from another random artist. Toggling the script on/off can be done via the configurationwindow of Shaneh's plugin.
Would be nice if we could switch a script on or off with a right clic instead of the config window ...
I'm planning to write a "party shuffle" similar to Itunes' one using this "active script" feature. But it would be very useful to lauch or stop it quickly from the "Script" menu !
neFAST
26th December 2004, 15:12
Finally I decided to trigger "Three from one" with a specific track header. So when I launch my playlist with that fake track, 3from1 is active. And when i listen to a track or an album it's off.
But (cause there's a but) it seems that Activewinamp won't remember the choose "Running Scripts" after a restart !
Anything planned to fix it ?
' +----------------------+
' | Three from one |
' +----------------------+
' Automatically enqueues a new song each time a song is played. Plays 3 songs in a row per artist
' Written by CaAl
Dim playingartist, playingtitle, prevartist, prevtitle, prevprevartist, mlq, q1, q2, q3
Randomize
Sub Application_ChangedTrack
if playlist(1).filename="X:\-----Three from One--------------------------.x" then
' Reading in the required artist/title-fields. Assumption: all songs have ID3 tag. If not, bad things could happen, but I don't really care
playingartist = playlist(playlist.position).artist
// code ....
end if
End Sub
shaneh
30th December 2004, 01:39
AW doesnt remember 'running scripts' in the same way Windows doesnt remember running programs. If you want something to start at startup, name it 'startup_x.vbs'.
You could write a startup script which checked an .ini file and launched any other scripts depending on whether you want them to run at startup.
AW currently just uses the running script dialog for running scripts. I may include another sub menu for running scripts which lets you stop them more easily. Theres a bit I need to do with regards to script management (hot key callbacks, menu item registering/callbacks, etc etc..).
neFAST
3rd January 2005, 22:18
your right, startup mode is exactly what i was looking for ! I thought startup would only launch the script once.
I've another question, I was still using gen_script.dll and I recently installed the gen_activewa.dll version.
Since my script computing a "smart random" is now 10 times slower than before !!!
The query medialibrary.runqueryarray("type = 0") takes ages to complete with big libraries :(
Any idea to optimize that ?
shaneh
5th January 2005, 10:51
Im guessing theres an issue with the meta data retrieval on creation of a "MediaItem". I will look into it soon.
Wabiloo
11th January 2005, 16:32
Hi, and sorry for this stupid post, but...
I just installed ActiveWinamp, downloaded from the plugin pages, and all reviews mention a help file. However, I can't find it. I can see the scripts in "Scripts" and some external applications examples in "AWExamples", but cannot find the help file...
[edit]
Found it, if it's gen_activewa.chm.
Apparently I can't delete my post so it'll have to stay...
Never mind he!
Wabiloo
11th January 2005, 21:46
Originally posted by shaneh
You need to put id3com.dll wherever you like, then run
regsvr32 id3com.dll
I tried the same thing with id3lib.dll v3.8.3 downloaded from their sourceforge website, but got the following message:
"id3lib.dll was loaded, but the DllRegisterServer entry point was not found.
This file can not be registered."
Any idea what could be the problem? (sorry I'm not used to programming under Windoze)
shaneh
11th January 2005, 23:28
id3com not id3lib.
Wabiloo
11th January 2005, 23:45
Originally posted by shaneh
id3com not id3lib.
Ah, OK, not the same thing. I read the id3com is a wrapper, whatever that means.
Couldn't find a compiled version in their distribution though, so I had to find it somewhere else.
Do you have any idea where I could find the object reference for it?
saivert
12th January 2005, 13:36
ID3Lib is a completely different project. You don't even need ID3Lib cos' ID3Com has built in functions for reading tags.
Wabiloo
13th January 2005, 08:37
Is it possible to create a ChangedPlaylist event, that would be triggered every time the playlist is modified (addition, deletion, swap, etc.)?
This is for me to write an external application that would interact with current software I'm using so that I have total control over the playlist, but can still let other applications change the playlist and be aware of the changes.
shaneh
14th January 2005, 10:06
@saivert: id3com uses id3lib. Much of the source is shared between projects either as source or binary. If you download the id3lib project, you will get the id3com source as well. There are some prebuilt id3coms around.
@wabiloo: Thats possible, however it would fire far too often. That message is fired far more often than is practical to do something with. If you take a look at other playlist replacement programs, they use alternative methods than re-reading the playlist every time this message is fired. Its just not practical to do.
Wabiloo
14th January 2005, 10:51
Originally posted by shaneh
@wabiloo: Thats possible, however it would fire far too often. That message is fired far more often than is practical to do something with.
Ah, I didn't think it would fire that often, unless obviously it fires every time winamp skips a song as well...
If you take a look at other playlist replacement programs, they use alternative methods than re-reading the playlist every time this message is fired.
Well, that's precisely my problem. The programs I know that try to do something of the sort are just crap and I end up with playlists completely out of sync, with the consequence of the external program telling me song X is playing when Winamp plays song Y. Bloody annoying!
Would you mind possibly giving me a couple of references of playlist replacements programs you know do that well, or pointers to source that explain a proper method to do so?
Many thanks!
shaneh
14th January 2005, 11:08
Mexp or whatever its called does this. It uses a trick where it just keeps 3 items in the playlist at anytime, and uses its own external playlist. It then updates the winamp playlist with the relevant 3 items whenever is necessary. (3 items for: current, previous and next).
You will be hard pressed to find a playlist replacement plugin that does it well, this is due to a limitation of winamp and not the fault of the plugin.
I would really like to see the playlist implemented in the media library, but this will never happen with development of winamp now stopped, and it simply not being practical to synch playlists with winamp in its current state.
Wabiloo
14th January 2005, 11:45
Originally posted by shaneh
but this will never happen with development of winamp now stopped,
Are you aware of something I'm not?
There's a post on the Winamp website that denies this:
http://www.winamp.com/about/article.php?aid=10627
shaneh
14th January 2005, 11:52
Well I'll believe it when I see it. Bug fixes dont count as development IMHO. And certainly not in anyway hinting towards the kind of development required to implement any more features such as this.
The guy who wrote that post is from winampunlimited.com and isnt a winamp developer AFAIK, so Id not put much faith in something like that unless it comes from someone who would actually be doing any development.
inthegray
14th January 2005, 15:17
i've reason to believe that wa is still being worked on, and will very likely see a noticeable increase in development activity in the next year.
herd
14th January 2005, 18:22
Dear Shaneh, I have a small suggestion:
Controlling winAmp from an external COM controller application is very easy thanks to your plugin. However, C++ Apps can encounter problems when the user closes winAmp by the UI. Any further access beyond the destruction is denied (RPC_E_DISCONNECTED) since you seem to call CoRevokeClassObject and shut down correctly.
Please consider implementing two aditional events to notify your clients of:
1. That you're about to shut down, e.g. OnAboutToTerminate() thus giving the caller a chance to cleanup before all your objects are destroyed / detached.
2. OnTerminate(). App should never get this if it did a proper cleanup.
This way, the caller can clean all memory tied to WA resources and avoid memory leaks.
TIA,
Hakan
DION03
16th January 2005, 23:13
I've looked through here a bit and haven't quite found the answer I am looking for (great tool by the way). I want to work out a code to run through albums that I choose and create a log for missing tracks, or even better to create a "placeholder" mp3 in a directory and add new track to library.
The tricks:
- Name the file %artist% - %album%/%tracknumber% - %artist% - Missing Track.mp3 for metadata.
- "Missing Track" title allows for a smart view in Media Library (title = 'Missing Track').
- Go to smart view in album/artist mode and find all incomplete albums and missing tracks at your fingertips!
Why not "add seperator" or why anything?
- I have tried a custom "add seperator" to each incomplete album one by one and saving as a playlist. This works but is slow and doesn't help point out missing tracks.
- When there are too many incomplete albums and tracks to remember what needs updating.
- The aesthetics of having a track for every spot in an album, complete or not.
How does it "think"?
- What is the highest track number, according to the library?
- Is there supposed to be a track before this one?
- Is there a library entry for this track?
- If not, assume there is no file for it and create the placeholder file.
- Repeat through to track #1.
I'm not technically expert here, but I know the logic. Can anyone help? I think a lot of us could use it. I should point out that this would be for an established mostly-accurate library and should only be executed on albums you know to be largely complete.
I have tried creating blank text files and changing the extension. This serves the purpose of adding a library entry and the file did keep idv3 tags but I am sure there are other issues with this.
shaneh
17th January 2005, 01:06
@herd: I will add that in when I tidy it up and decide on how to release later versions and open source it etc. I need to read up on the standard practice of modifying COM components after they are released. I dont want people to have to recompile their programs for every new release, or have them crash when using the wrong one etc, so I will need to do it right.
I worry though that sending that event then effectively shutting down may cause problems. As the event source will have disappeared by the time the target gets the notification. Threading, message pumping, apartments etc all come into play and it becomes a bit of a nightmare.
The proper solution is to actually prevent winamp from shutting down if there are any connections. msnmessenger does this for example when outlook is still open. I could do this in winamp too. Will need to look into it.
@DION03: not too sure what you going on about :P Im guessing you just want to create placeholder .mp3 files for missing tracks from an album somehow.
Unfortuantly AW doesnt currently allow you to just add stuff to the library, though you can create files. You could then send a window message to the ML to rescan watched directories after you are done I suppose. (note, loading a file with LoadFile then modifying a ml metadata value may add the item to the ml too).
The best way would probably be to make a sendto_ script, and have it look at the album of the selected file. Then query the ML for that album, and sort the results by track. (or just sort the selected songs by track without doing a query if you want to select the actual album yourself).
Then just step through each one and put in a placeholder file/s if the track number increments by more than one.
CaAl
19th January 2005, 07:56
Hmm. Since a couple of days, the plugin doesn't work properly anymore. I have two startupscripts (that log all the songs that are played) - these work fine. But all the scripts I want to run from the playlist or the Media Library (e.g. randomize selection and increase playcount) don't work anymore :(
I don't know what could be wrong - I haven't removed DLL's from the plugin folder or something like that.
Can someone suggest how I can fix this problem?
saivert
19th January 2005, 08:56
What about implementing more structured scripts like those WSF files. Using WSF files are much more robust than using plain scripts. You could create a WSF like format for use with AW (e.g. AWSF - ActiveWinamp Script File). This file will contain XML tags like '<script language="VBScript">' and '<JOB id="id">' so you could put more scripts inside one file. You could also specify special attributes/tags for defining custom menu items and behaviour. Here is an example of what an AWSF file would look like:
<awsf>
<actions>
<action event="onstartup" trigger="startup1" />
<action event="onstartup" trigger="startup2" />
</actions>
<menu>
<menuitem trigger="sort_playcount">Sort files after playcount</menuitem>
</menu>
<sendtoitems>
<menuitem trigger="copytofolder">Copy to MP3-player</menuitem>
</sendtoitems>
<script id="sort_playcount" language="VBScript">
' do work here
</script>
<script id="startup1" language="VBScript">
' do work here
</script>
<script id="startup2" language="VBScript">
' do work here
</script>
<script id="copytofolder" language="VBScript">
' copy to mp3 player...
</script>
</awsf>
PS! Can some moderator edit neFAST's post so it doesn't expand the forum page so much?
CaAl
19th January 2005, 09:20
Originally posted by CaAl
Hmm. Since a couple of days, the plugin doesn't work properly anymore. [..]
Can someone suggest how I can fix this problem?
I found the solution: a couple of days back I've set the option "use advanced title formatting when possible" (under general prefs/titles) to off. Now I switched it back on, and the scripts all work fine.
Seems a bit weird though, that this was the couse of the problems...
Thunder Pussy
21st January 2005, 18:24
Hi, I need help (again). I've just added my my out-of-rotation folder to the ml db to take advantage of ml caching in dynamic library. I'm having to edit all of my scripts to accomodate this. There are 3 scripts I use that follow the same format, and I need to edit them so that they include only songs from "E:\Music\". How do I fix this? I get errors when I add filename has E:\Music AND... Thanks very much.
Randomize
x = playlist.getselection()
if ubound(x,1) > 0 then
mlq = medialibrary.runqueryarray("artist = """ + x(1).artist + """")
i = 0
for each track in mlq
i = i + 1
swapitems mlq(i), mlq(Int((ubound(mlq,1)) * Rnd + 1))
next
for each track in mlq
if strcomp(track.filename, x(1).filename) <> 0 then
track.insert(x(1).position)
end if
next
end if
quit
sub swapitems(ByRef val1, ByRef val2)
set temp = val2
set val2 = val1
set val1 = temp
End Sub
katemonster
26th January 2005, 16:43
Any news on a website to post scripts people have written? I'm trying to figure out how to do this from scratch basically, and I think it would help me to have more scripts to look at. As it is, I don't even know that what I want to do is possible--would it be possible to write a script to generate a playlist choosing tracks weighted by rating and various other factors? Basically, a smarter shuffle...
CaAl
27th January 2005, 07:52
Hi Kate,
When you read the messages in this thread, you'll encounter some scripts which might help you.
I don't think such a smart shuffle thing is (easily) possible - I've been working on it myself for quite some time. The problem is that you need to make some kind of database with your songs and their ratings, because reading the ratings from the MP3tags will work too slow (and I'd like more than 5 categories in my rating).
So you have to write some dataexport and dataimporting scripts, etc. It can be done, but it's a lot of work...
shaneh
27th January 2005, 08:20
I have some web space and domains etc, but just lack of time to do up a site properly.
A weighted shuffle wouldnt be impossible, just require a bit of work. The rating info isnt that difficult to extract if its stored in the media library, just do a query and look at the ratings, playcount last played etc and work with that.
The easiest way to do it is probably to turn shuffle off, then fill the playlist with items based on whatever algorithm you choose. The algorithm would be the most difficult part.
Otherwise you can do a sort of 'party shuffle' thing, where you just have a few items in the playlist, and add new ones as the songs change.
You can get media library items by simply doing:
mlitems = MediaLibrary.RunQueryArray("Rating > 0")
'sort mlitems based on criteria
for each song in mlitems
song.enqueue
next
As you can see, the algorithm to sort/mix/whatever the items would be the most difficult part.
I have a sort of weighted shuffle thing I picked up somewhere a while back. Dont think it works too well, but you can take a look at it:
Dim songlist(), i, rndtotal, lasttrack
Randomize
Sub Application_ChangedTrack
playlist.deleteindex playlist.position - 1
ReDim songlist(playlist.count - 1)
i = 0
for each song in playlist
songlist(i) = song.rating
i = i + 1
next
i = 0
ratingtotal = 0
'calc average
for each song in songlist
ratingtotal = ratingtotal + songlist(i)
i = i + 1
next
ratingavg = Int(ratingtotal / ubound(songlist))
i = 0
rndtotal = 0
for each songr in songlist
if songlist(i) = 0 Then
songlist(i) = ratingavg
End if
rndtotal = rndtotal + songlist(i)
i = i + 1
next
rval = Int((rndtotal - 0 + 1) * Rnd + 0)
runningtot = 0
i = 0
for each songr in songlist
i = i + 1
runningtot = runningtot + songr
if runningtot >= rval Then
playlist.position = i
play
lasttrack = i
exit for
end if
next
End Sub
Crestronite
30th January 2005, 18:04
A real newbie Q. I am trying somewhat succesfully to use ActiveWinamp from VB6. Most things are working but I wish to add a named file eg "C:\test.mp3" to a specific place in the playlist and then go on to manipulate the playlist position so it is played, and then delete it and resume. So adding to the end will be fine.I really don't want that track to become part of WinAMPs media library either. But I am struggling on how to add the named file (in VB6) not as VBscript. It would be most appreciated if someone could quickly show me how ??
Also if anyone has any more extensive VB6 code using ActiveWinamp they could share as a learning exercise that would be great.
Chris
shaneh
31st January 2005, 00:46
I dont feel like installing VB6 on my machine, but AFAIK its not much different from vbscript at least in syntax.
To do that in vbscript, you would do something like:
mi = loaditem "C:\test.mp3"
mi.enqueue
oldpos = playlist.position
playlist.position = playlist.count
play
playlist.position = oldpos
playlist.deleteindex playlist.count
Edit: If youd like to not delete the item until it is done playing, you would need to trap the play state changed or song changed event, and then delete the item. However winamp will continue playing the item even though its not in the playlist. Its kinda weird though, and will screw up a few things that get current playing file info based on the current playlist position in wianmp. IMHO it is a fault in winamp.
saivert
31st January 2005, 07:11
shaneh's ActiveWinamp plugin is actually an excellent scripting platform for Winamp. I have had some time experimenting with it and you can actually convert a lot of small plugins (dll files) into scripts for ActiveWinamp. If you ever used the "Find in Explorer" plugin to get a new item in the playlist context-menu to locate a file in the Explorer you may now do this as an ActiveWinamp script:
VBScript
Option Explicit
Dim wsh, sel
sel = Playlist.GetSelection
Set wsh = CreateObject("WScript.Shell")
If UBound(sel) = 1 Then
wsh.Run "explorer.exe /select," & sel(1).Filename
End If
Quit 'end script
PS! And please... what's all those WIDE posts for? Keep your CODE sections broken into multiple lines. Use the underscore to split lines in VBScript. Like:
Dim x
x = Playlist.GetSelection
For y = ubound(x) To 1 Step -1
set sep = LoadItem("x:-----" + _
x(y).Album + _
"-------------------.x")
sep.Insert(CInt(x(y).position) -_
1)
Next
Quit
And please use capitalization when writing VBScripts. It's much easier to read then. Refer to the VBScript coding style info (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/script56/html/vbscodingconventions.asp) from Microsoft.
All lowercase isn't neccessary in order to get the script running. shaneh uses Mixed case in his documentation so why shouldn't we?
Crestronite
31st January 2005, 15:19
Originally posted by shaneh
I dont feel like installing VB6 on my machine, but AFAIK its not much different from vbscript at least in syntax.
To do that in vbscript, you would do something like:
mi = loaditem "C:\test.mp3"
mi.enqueue
oldpos = playlist.position
playlist.position = playlist.count
play
playlist.position = oldpos
playlist.deleteindex playlist.count
In VB6 I have a global declaration
Dim WithEvents aWinAMP as ActiveWinamp.Application
In my Form Load() I have
Set aWinAMP=CreateObject("WINAMPCOM.APPLICATION")
Most things seem to work ok including the event callback
In a different subroutine I have
Dim mi as MediaItem
mi=aWinAMP.LoadItem("C:\temp.mp3")
mi.enqueue
... etc
but the loaditem assignment errors with invalid use of property - - although it looks as though the right hand side indicates it returns a MediaItem , I think it actually returns a string. I guess I'm being really stupid here ?
mi= aWinAMP.Loaditem "C:\temp.mp3" is not a valid syntax
msgbox aWinAMP.LoadItem("C:\temp.mp3") gives a "C:\temp.mp3" message and the filename is not checked in anyway as existing as it works for anything.
Chris
EDIT: AHHH - and the light went on... ;-)
Set mi=aWinAMP.LoadItem("C:\temp.mp3")
DUH ! Chris
shaneh
1st February 2005, 00:53
Yep, I forgot the brackets. I was going to edit it in but I figured youd work it out, the example in the help file for loaditem uses brackets.
You should be using 'activewinamp.application' not winampcom.application. But if you can get loaditem to work, I guess you are using the correct one.
I thought the 'Set' may have been needed, but I think its not necessary under vbscript.
saivert
1st February 2005, 07:13
I have made an update to your ActiveWinamp examples. Here it is:
NxS-ActiveWinamp-stuff-Setup.exe (http://inthegray.com/saivert/cgi-bin/topdl/download.pl?file=NxS-ActiveWinamp-stuff-Setup.exe)
Crestronite
1st February 2005, 11:33
Originally posted by shaneh
You should be using 'activewinamp.application' not winampcom.application. But if you can get loaditem to work, I guess you are using the correct one.
Sorry yes - I was using the right one - just typed the wrong one in the message as I was trying a couple of different approaches. All is working now.
I have been trying three possible scripting solutions for my projects all of which have different strengths and weaknesses. ActiveWinAMP is my favourite in terms of most features and responsive developers (thanks !) - but I do need control of multiple instances on one machine (see thread http://forums.winamp.com/showthread.php?s=&threadid=206384 ) . This is because I use six channel (surround sound) audio cards divided into 3 stereo pairs each driven by a different WinAMP instance for 3 audio zones. I take it from your reply that launching WinAMP using the optional "class" parameter as Lion12 was doing earlier in this thread will not help either - even if I ensure my WinAMP instances are all up and running prior to my application. I am guessing I can't control which winamp instance I'm connecting to or even 'step' through multiple instances to identify a particular one by an ID or by recovery of the class name or something. ..
Chris
shaneh
1st February 2005, 11:53
snipped.
/EDIT: Ignore that ramble.
Im looking into adding proper multiple instance support. Will see how it goes. I'll upload a test version here. I will need to disable a few other things to get it working, but it may be useful for you to play with.
shaneh
1st February 2005, 13:18
Heres a rough version of AW which supports multiple instances a little better. Note however its not fully tested.
Also note, it uses the REGCLS_SINGLEUSE registration in the ROT. What this basically means is, the active instance of the object is registered in the system, but once an external application grabs that object it disapears in the table.
So, you cannot re-grab the ActiveWinamp object once you have used it externally. ie, the registration assumes a new copy of the .exe will be started for every 'object grab', and the .exe will be basically terminated once finished. If this isnt the case, it causes problems when you go to use AW again, either from the same application or a different one. So you have to keep the reference around, lose it, and you have to start another copy of winamp and get another one.
So basically, this version of AW is for multiple use only, and just for playing with. I might look into a better solution using mo****rs and window classes.
Crestronite
6th February 2005, 14:19
Hi.. thanks for the changes you made here, this is working well for me in separating my instances, so I'm half way there. I have multiple instances running and controlled OK :-)
As I was previously set up I had several WinAMP folders and I used to launch each WinAMP individually , from its own folder and the preferences were set such that each used different output options effectively feeding the audio to different zones. How might I accomplish that using this type of solution as my instances are identical, would I in some way be able to load a different ini file in each instance perhaps , or set the output somehow ?
Alternatively if I wish to control an already running instances of WinAMP I think you are saying that is going to be not possible as I cant get at the object. I was just thinking of launching my 3 independant zones and picking them up that way.
Chris
<edit> What I think I shouldn't be doing is using 'CreateObject' and creating a new object but instead picking up one of the mutiple existing instances perhaps using GetObject.
Crestronite
6th February 2005, 17:36
Yes - just needed to use GetObject - and I can pick up the already existing instances so this is very suitable for what I need, (although as you say it can only run once without having to restart the WinAMPs) .. Many thanks
Chris
shaneh
7th February 2005, 00:50
I am working on a new implementation which will allow you to hopefully "GetObject" using the window class name of the started winamp. Im still looking into it but hopefully it will work ok.
I think that version I posted here is a bit broken, events may not work properly with it. Basically its just for playing with until I get a proper version released.
JohnKane
12th February 2005, 00:48
First off, let me say THANK YOU for developing an activex COM object for Winamp. I had been struggling for some time with WinampCom. While this did the trick initially, it has limitations with regards to creating multiple instantiations. In my application, the com object resides on a server and is called by clients. If a client's session was terminated, the COM object remained. Subsequent client calls spawned new instantiations, and then the COM object stopped working. There is no way to get a handle to an existing object instantiation that could find with winampcom. This was a show stopper and I had almost given up on this project, when I found your plug-in posted.
So I for one appreciate the single instantiation operation. I am going to run some tests to see what happens when a client session terminates (hopefully it will work.)
One small suggestion: I got the object up and running very quickly for play, stop, pause, etc., assuming I had used the UI to load a playlist. But I struggled with trying to get a new playlist loaded with the com object. I had tried Loaditem, Getitem etc, and several combinations. After running through this thread a few times, I finally found the missing piece, the enqueue method needs to be called after the load. I'm not a winamp power user, so this was extremely non-intuitive for me. (Maybe thats just me) A little bit of text in the help file or an enqueue method example would have helped me. I couldnt find any samples that showed a new playlist being loaded.
I'll keep plugging at this to see if it solves my problem, but initial tests look promising.
shaneh
12th February 2005, 01:29
Yes, enqueue is what you want.
LoadItem is just a way of creating a MediaItem and setting the filename to the one you specify. A MediaItem is essentially a representation of a file, which also caches meta data about that file if and when you request it. Consider LoadItem to be the class factory or constructor if you are familiar with OOP.
Once you have that MediaItem, you can call the various Winamp IPCs that require a filename, such as IPC_PLAYFILE, and the filename that is used is the one thats contained within the MediaItem in question.
The use is a bit different to WinampCOM, which is basically just a proxy for the API calls. ActiveWinamp was designed to be a little more 'object orientated' which leads to a better design in the long run IMHO. (ie, it lets you have an array of mediaitems and enqueue the ones you want etc instead of having to maintain your own array of filenames) People familiar with OOP should hopefully find it relatively intuitive. However coming from WinampCOMs design I can understand it may seem awkward.
I will be retooling the help file a bit in the next release with some more helpful information other than just a reference. Its currently not much more than a re-generation of the typelib with a couple lame examples, a couple of which are broken :)
The Enqueue method was used to represent the IPC_PLAYFILE API 'call', because that is what winamp essentially does with the file passed.
With this is mind, if winamp were able to enqueue playlist files (.m3u) via this API call, you could simply do:
set mi=loaditem("c:\pls.m3u")
mi.enqueue
But winamp just enqueues the file and doesnt parse the m3u. AW doesnt have support for IPC_CHANGECURRENTFILE yet, I am not sure exactly how this behaves, but it might let you load playlists, and play files with resetting the playlist. I will look at adding it in if so.
With regards to the single instantiation, AW is a singleton COM object. So multiple clients are actually using the same COM object as well as the same winamp.exe. I am working on a way to support both multiple and single instances by letting clients use GetObject with a window class name as a mo****r. This wont affect anyone using AW+winamp in single instance mode, but it will allow people to obtain different instances of AW+Winamp if they needed to.
JohnKane
12th February 2005, 13:41
<But winamp just enqueues the file and doesnt parse the m3u. AW doesnt have support for IPC_CHANGECURRENTFILE yet, I am not sure exactly how this behaves, but it might let you load playlists, and play files with resetting the playlist. I will look at adding it in if so.>
Hmm, this isn't what I was seeing.
If I do the following using VBSCRIPT:
set objtest=objWinamp.LoadItem("C:\Program Files\Winamp\songs.m3u")
objnew=objtest.enqueue
Then winamp loads the whole playlist, and not the m3u filename itself.
However, I ran into trouble when I tried to use a string variable for the m3u path:
filename="C:\Program Files\Winamp\songs.m3u"
set objtest=objWinamp.LoadItem(filename)
VBScript bombs on a type mismatch. I think this is because when you add parens around a method parameter, vbscript passes by reference, and the LoadItem method is expecting a string.
Initially thinking the method was expecting quotes, I tried the following:
set objtest=obj.Winamp.LoadItem(chr(34) & filename & chr(34))
Now this didn't bomb out, but loads the playlist with a single entry "songs", equal to the name of the m3u file. (This sounds like the behavior you were expecting with regards to the loaditem operation. But winamp is confused by this, and tries to play the "songs" mp3, which doesn't exist.
In other cases like this, I have been able to Omit the parens around the method parameter to force passing by value, but this also bombs out the LoadItem call "expected end of statement".
shaneh
12th February 2005, 14:24
Ah yes, if its a valid m3u it will enqueue the whole playlist. I had a typo in my test and was loading the wrong file.
That behaviour is strange. It seems to be largely a problem with vbscript in general as I have seen some postings with other people having similar issues with COM-vbscript integration.
It is most certainly a ByVal/ByRef problem. LoadItem expects a BSTR*. This is unusual, as it is a [in] paramater only, every other [in] only paramater for the other functiones require just a BSTR. (no pointer*). I believe a BSTR is just a pointer to a lower level string with a ref count so its always passed by pointer in the low level implementation anyway. But for some reason I had made it a pointer to a BSTR, which shouldnt be needed unless it was acutally returning a modified BSTR.
I just took a look at the code and changed it to BSTR instead and it works ok. This will unfortuantly break anything that used it before, except script code.
What I could do is just add another method, LoadItem2 which behaves in this new and correct way. There is nothing really wrong with the other method, other than just not being script friendly.
Its not good form to change an interface like that once its published, but it really depends on how many people are using that method in compiled languages as to whether it will be ok or not.
Ive attached a copy of AW with the fixed method, plus it fixes the .position and .execvisplugin implementations.
JohnKane
12th February 2005, 15:26
Wow, now thats what I call support! Thanks.
I hear you on the BSTR issue. I struggle with them any time I need work with Strings and COM objects. Everytime I think I have it down, I run into a similar issue.
Since passing the string as a variable was giving me a hard time, I bypassed it temporarily and just hardcoded a filename. This got my playlist loaded via the Com object.
However, if I try to execute a Play method across the COM interface, I bomb out with the following:
Winamp.exe
The instruction at "0x0407869d" referenced memory at "0x00000028". the memory could not be read.
I should note that in this case, I am calling ActiveWinamp via ASP(Server.createobject) on a windows server. This calls the com component as an automation object (no visible gui on the server).
I highlight this because if I instantiate ActiveWinamp with vbscript inside html (client side), the play method works and doesn't bomb out.
shaneh
13th February 2005, 00:07
It seems strange that there is no visible object, Im guessing windows server blocks that somehow. As winamp does not honour the /embedding or /automation switches, and AW does not attempt to look at them either. So winamp should just load as if it were started normally. Perhaps ASP runs under its own desktop station thing or something like that.
This sounds like a bug in winamp trying to deal with being launched in this way rather than AW. AW does nothing more than a sendmessage(play) to the window then returns on that method. Do the other methods work? It could be something that winamp attempts to do when playing that causes the problem. Did winampCOM work and play when launched like this?
Another possible reason is the events firing back causing the crash. If WinampCOM works ok, Id be pretty certain this would be the cause. Although winampcom does attempt to do some stuff with the /embedding and /automation switches, and uses multiple instances which could also be the source of the problem.
A workaround could be to simply start winamp beforehand. Because AW is a singleton com object, every 'createobject' etc just grabs the running instance. Which, if its run beforehand, will be a GUI instance running on the desktop. Thats assuming ASP is able to grab that instance through createobject, which it may not if its running on a different desktop station.
JohnKane
13th February 2005, 14:31
In ASP and w2k server, COM components launch without GUIs (automation servers). WinampCOM also works like this. WinampCOM's problem (for my application) is that it spawns multiple instances, which it can't actually service. So if a client makes a createobject call, and one already exists, a new instantiation is spawned, but the com object data gets scrambled. There is no way to correct this without manually killing the extra instantiations, and so thats a non-starter. ActiveWinamp doesn't do this, and I thought I had a working solution, until the crash.
All the other methods I have tried on the server with ActiveWinamp have worked, LoadItem, Playlist.Position, etc. As soon as I call Play, the winamp process crashes with the error I listed previously. When I call it locally as a client side activex object, its ok.
Having the Winamp GUI open ahead of time doesn't help. Even with ActiveWinamp being a singleton, a new winamp process is spawned, because ASP opens the COM component in a different user context. The instantiation of winamp from the gui is owned by the logged in user. But ASP processes run under different system account context.
Is there way another via ActiveWinamp to get a play command sent, like the general 'sendMSG' message? I think WinampCOM used the old message interface (40xxx style). That may be what you're doing internally anyway.
So close, and so far... and I doubt you have w2k server/IIS laying around to try instantiating in this fashion. Did you write the COM object in VC++? I could configure my server run off the vc++ debugger and try to see whats going on, but that would require the full project/source. (And of course that's a pretty big request to make.) If its really in winamp space, then I'm stuck. But winampCOM works, so that gives me some hope.
shaneh
13th February 2005, 14:58
Im guessing it could be something to do with the events firing back. The code for Play is basically:
STDMETHODIMP CApplication::Play(void)
{
SendMessage(plugin.hwndParent,WM_COMMAND,40045,0);
return S_OK;
}
So I think the bug is related to what happens *after* the play is called. I doubt ASP has a sendmessage function anywhere, but if there is or something you can use, you could try sending this WM_COMMAND to winamp. But as I said, I think the events firing back is causing the problem.
AW was written in VC++ with ATL.
I have plans to relase the source to ActiveWinamp, so that is not much of a problem, however it really needs to be tidied up a bit first, there are some known bugs with the thread pooling for scripts, but that doesnt cause too many issues. Its also full of badly named variables and filenames etc etc, but its not too bad if youre just looking at the COM objects implementation. Its mainly the internal script hosting that gets a bit messy.
Check your PM
saivert
17th February 2005, 06:25
I guess you will be setting up a site on SourceForge then?? With full bugtracking and a team. (Will join you).
shaneh
17th February 2005, 09:52
Yes, hopefully soon. Theres a bit of code tidying up and licensing decisions before then though. I wouldnt mind it being part of the offical winamp distribution. Winamp really should have some automation support to remain competitive.
As for WSH style script files (re your PM), you could work on that feature if you wanted, though the whole internal script hosting needs a bit of an overhaul. The thread pooling for the scripts is a bit broken, and the way the script objects are started is fairly inefficent.
I think better support for starting and stopping running scripts, multiple instance support, ability to dynamically add and remove menu items and hot keys, more and better events, better ML methods etc also need to be worked on. Plus internal objects need to be imporved a little, to reduce the need for all the fixed sized buffers etc.
So theres plenty to be 'fixed' before adding new features which probably wouldnt be used by most people. Remeber that you can run scripts external to winamp if you want complicated WSH object support, the AW object is just accessed out of process rather than in process.
saivert
17th February 2005, 12:56
dynamic add and removal of menu items can be made possible by implementing WSF type file support. Use special XML tags to define the menu items and use methods on a IMenuItem interface to show/hide.
WSF files would also remove the need to have special filenames for scripts ("playlist_", "sendto_" and "startup_" prefixes) because this will be specified using tags in the WSF file. And you can specify the script language using the SCRIPT tag's language attribute.
You could possibly add more special tags to define more complicated behaviour.
JohnKane
19th February 2005, 18:05
Shane,
FYI: after a lot of testing, it looks like both WinampCOM and ActiveWinamp objects behave the same way with Winamp 5.0. Executing the Play method from ASP on w2k server causes an exception in winamp (the classic 'memory could not be read' (Songs do start playing for a few seconds before the crash occurs, I was missing this subtlety).
I tried a good deal of experimenting to get around it, but no dice. I'd love the write a Winamp bug against it, but I would probably be flogged since it shows up in plugin space. Not to mention I don't expect there are too many people running this under ASP on a server.
WinampCOM didn't have this issue in Winamp 2.78 or Winamp 3. Of course, these versions won't work with ActiveWA, so thats out too. Since both WinampCOM and ActiveWinamp objects are simply using a SendMessage Play call, I doubt its related to anything in the third party code. Most likely there is some issue with the call in '-embedding' mode, since this is how all COM objects are instantiated in ASP.
Oh, one other thing: I can't make "SendMsg" calls from VBscript in ASP either. I think the wparam, lparam types can't get across the COM interface. VBScript throws an "unsupported automation type" error. Maybe you could consider passing the args as longs, since these seem to pass properly within the variant constraints of VBscript. I guess this is another case where you may need an alaternate version of the method.
shaneh
20th February 2005, 00:48
WinampCOM strips the -embedding argument AFAIK, so I suspect Winamp just cant handle running in the 'headless' state, or with those permissions or whatever ASP does to running processes. There might be something you can do with ASP to let the process run as a standard process.
The SendMsg call was done like that because VBScript doesnt support unsigned longs, only signed longs. It may be possible to just use a long, but at the time of writing that was the solution I researched and seemed to be what should be used.
shaneh
20th February 2005, 06:40
Also, you might like to check with this other scripting plugin:
http://www.pretentiousname.com/gen_scripting/
to see if you have any luck.
JohnKane
21st February 2005, 01:23
Shane,
I have had some success with getting this to work, but I had to edit the identity that the process launches under. This forces the gui to appear, and the problem went away for now. This requires having an account logged on to the server at all times, but at least it's not crashing.
I still go back to the fact that winampcom worked under winamp 2.78, so I know its not entirely ASP's fault that it doesnt work in 5.0. But I have something to work with now.
VBScript definitely doesn't like the params in SendMsg/PostMsg calls. I'll have to take a look and see if there's another alternative.
Thanks,
John
shaneh
21st February 2005, 01:38
It could be something that winamp is doing in verison 5 which is causing ASP to be "at fault" if you know what I mean. For example, modern skins might be causing v5 to request some graphics primitive that isnt allowed when running under ASP (just an example). Winamp was clearly not intended to be run in this way :)
Ill look further into the sendmsg stuff soon. I do recall it working for me with vbscript, though perhaps I changed it, as I just checked and it doesnt seem to be functioning too well.
shaneh
24th February 2005, 04:44
Please see:
http://sourceforge.net/projects/activewinamp/
For source and development discussion. Pay careful attention to release notes, news items, trackers and forum posts before diving in.
CaAl
24th February 2005, 11:52
I want a script that removes all songs just played from the playlist. When I run the script below, Winamp crashes. I don't understand why. Anyone? Tx in advance:)
Sub Application_ChangedTrack
If playlist.position > 1 Then
playlist.deleteindex(1)
End if
End Sub
saivert
28th February 2005, 08:20
How about writing a NT service application that runs in the background and receives commands from an ActiveX Scripting Object (ASP) through named pipes or something. Then It could hook into the Windows Station running Winamp and send messages to it. Just an Idea.. I would certainly use a lot of time writing the myself.
frozdsolid
14th March 2005, 03:47
I was playing a little with your scripting interface in C# and noticed that immediatly upon instantiating the COM object, winamp launches. I'm sure this behavior is probably relevant to the nature of COM. I don't know a whole lot about it so I can't be sure (I wish I did!).
To briefly explain why this behavior is relevant, I'm writing a small C# app that updates my AOL Instant Messenger (AIM) profile with the song I'm currently listening to. It relies on a dll that gets loaded into aim (my friend wrote it) that responds to a message that updates the profile. Currently I've interfaced with iTunes via COM, and everything is good. Now I'm adding winamp support.
The behavior of the app is such that if itunes isn't loaded, it just does nothing, and waits until iTunes is launched. Once it does, it starts responding to track change events and updating my AIM profile. If iTunes quits, the cycle repeats. Is this something that your interface can accomplish, or should I maybe write my own simpler winamp plugin that just sends out a windows message to my app on track change events?
shaneh
14th March 2005, 12:40
You can use "GetObject" instead of "CreateObject" to try obtain a running instance. It will return an error if its not running. I am not sure how to do this in C#, but Im quite sure there would be a way, its standard COM stuff. Otherwise you can just test with "FindWindow" or some other technique to see if Winamp is running.
There is no way to "wait" until winamp is launched. I dont know how you are doing it for iTunes, I was not aware iTunes broadcast a system message that it was starting. (that is what would be required to achieve that AFAIK).
frozdsolid
14th March 2005, 13:16
I take advantage of this weird behavior, in the iTunes COM object. If I instantiate the object, iTunes doesn't appear to open, but once it does open, the events start working fine. When it quits the object becomes useless, so I catch the on quit event and reinstantiate the object then.
So I guess I'll just write my own winamp plugin that would broadcast when it loads, then I can just use yours once it does....
shaneh
15th March 2005, 00:11
I would imagine iTunes is actually starting, have you looked in the process list? It is probably starting, but just not showing any GUI.
I think ActiveWinamp currently doesnt have a 'quit' event, so your plugin may need to broadcast that event too, unless you want to edit the source to AW to add it in. I wil add it in myself eventually.
frozdsolid
15th March 2005, 21:58
Yea, I don't see iTunes showing up in the process list but I have a feeling that it's somehow starting because iTunes loads a lot faster once i instantiate the object.
Once I started writing my plugin I realized that I could just add a bit more code to send out the song title (maybe using a memory mapped file) to my profile updating program, and not have to deal with some of the strange and seemingly unpredictable COM behavior (again, I'm not a COM expert, so this could be my fault -- COM just seems slow sometimes as it tends to hang the client and server if there are any sort of problems)
But your advice and activewinamp source code have been a HUGE help. I don't know how I would've figured out the proper way to subclass the wndproc and catch the necessary events without your source.
Thanks!
CaAl
16th March 2005, 09:39
Originally posted by CaAl
I want a script that removes all songs just played from the playlist. When I run the script below, Winamp crashes. I don't understand why. Anyone? Tx in advance:)
Sub Application_ChangedTrack
If playlist.position > 1 Then
playlist.deleteindex(1)
End if
End Sub
Because there hasn't been an answer yet, and I am still waiting for one, here's a repost.
So, what I want with my script: each time the playlist advances one song, the first song in the playlist (which thus has already been played), should be removed. The script I wrote was:
Sub Application_ChangedTrack
If playlist.position > 1 Then
playlist.deleteindex(1)
End if
End Sub
But, this doesn't work. As soon as the track changes, winamp crashes pretty nasty... :( Please, can anyone help me out here?
shaneh
16th March 2005, 09:53
Hmm, that script seems to work fine for me, thoughit does crash when there is only 2 items left in the playlist. Ive fixed it up a bit, and doesnt seem to anymore. Grab the lateswt .dll from the CVS.
http://activewinamp.sourceforge.net
CaAl
16th March 2005, 12:01
Originally posted by shaneh
Hmm, that script seems to work fine for me, thoughit does crash when there is only 2 items left in the playlist. Ive fixed it up a bit, and doesnt seem to anymore. Grab the lateswt .dll from the CVS.
http://activewinamp.sourceforge.net
thanks, now it works (and, yes, the script needed some additional tweaking and finetuning :))
dhorrocks
18th March 2005, 16:16
Hi
I've been making a program in c# using your brilliant app here.. I've used the dll and have now hit a problem.
trackArray = winamp.MediaLibrary.RunQueryArray("artist HAS blink");
That works fine.. the problem is how would I count how many items it's returned and use a loop on that? And how from that would I access each songs tracks name. I've got it working for artists looping. But this just seems impossible to get working
Any help would be appreciated.
shaneh
18th March 2005, 23:35
You just need to use the length of the array. ie:
Array trackArray = (Array)winamp.MediaLibrary.RunQueryArray("artist HAS Powderfinger");
MessageBox.Show(Convert.ToString(trackArray.Length));
Or you could use the newer version of AW in the CVS and use the "RunQuery" method which returns an object, which has a Count and enumerator etc. This is a bit faster in the short term than runqueryarray, especially when used out of process, but can be slower in the long term. ie, the MediaItem objects are created on demand, rather than creating and returning the entire array. But if you intend to inspect *every* item that is returned, runqueryarray may be the better alternative.
I may make some changes to the RunQueryArray method, as it should really be casting to "Array" automatically. I kind of know where to start with this, but we will see. AW 2.0 is starting to shape up nicely, and Im hoping it will hit the streets soon.
antu^jamban
28th March 2005, 13:02
This is a great plugin. I already use it for my widget LINK (http://www.wincustomize.com/ViewSkin.aspx?SID=1&SkinID=391&LibID=34). Thanks for creating it.
I'm having a problem. I tried using ATFString to get the sample rate (%srate%) but it returns 0. Is there anyway I can make it to work? Another thing I notice, the plugin didnt support VBR. Any chances we're going to have this?
Thanks in advanced. BTW, I'm coding in VB
shaneh
29th March 2005, 01:18
This is because AW gets the sample rate and bit rate using an API which is based on the currently playing file. ie:
#define IPC_GETINFO 126
/* (requires Winamp 2.05+)
** int inf=SendMessage(hwnd_winamp,WM_WA_IPC,mode,IPC_GETINFO);
** IPC_GETINFO returns info about the current playing song. The value
** it returns depends on the value of 'mode'.
** Mode Meaning
** ------------------
** 0 Samplerate (i.e. 44100)
** 1 Bitrate (i.e. 128)
** 2 Channels (i.e. 2)
** 3 (5+) Video LOWORD=w HIWORD=h
** 4 (5+) > 65536, string (video description)
Although bitrate is retrieved from the ML if available. I dont think Winamp provides an API to get the sample rate from anything but the currently playing song, but I could be wrong. You can see the source of ActiveWinamp at http://sourceforge.net/projects/activewinamp/ to see the exact implementation details. If there are particular changes required to better support such meta data feel free to make them.
You can use the following to make the above call:
mode = 0
x = SendMsg(1024, mode, 126)
msgbox x
saivert
29th March 2005, 01:36
Doesn't the ML database keep bitrate, samplerate and channel info about each song? I really think so or else it would be slow to browse through ones ML if one had over 2000 songs in a list.
shaneh
29th March 2005, 01:42
It keeps the bitrate, but there is no sample rate data AFAIK. There is no samplerate column in the ML so this has no effect on your browsing speed in the ML as it is never shown.
There may be a way to get the samplerate data, as the 'view file info' manages to do it for songs that aren't playing. Perhaps the get extended info API call has a sample rate meta field for mp3s. In ActiveWinamp, whatever tag you pass to the ATFString method first gets tried in the ML, then through the IPC_GET_EXTENDED_FILE_INFO_HOOKABLE call. Although srate is intercepted and uses the above call, which is only useful for the currently playing item. Which is actually a bit of a bug, as it should apply to the current Media Item instead, but its not really a big deal. If there is a way to get the sample rate of non-playing items, I will use that instead.
roytam1
29th March 2005, 10:51
I've some questions.
How can I set a selection? ActiveWinamp doesn't have playlist.selselect(number).
How can I enqueue a playlist without using media library? playlist(number).enqueue doesn't work.
shaneh
29th March 2005, 10:55
ActiveWinamp doesnt provide a means to set the selection. Winamp provides no such API so this isnt possible. If you can provide the code to set the selection, I can add it to aw. However I will not add mouse/keyboard emulated hacks.
You can enqueue a playlist file like so:
http://activewinamp.sourceforge.net/doku.php?id=examples:playlist:enqueue_playlist_file
If you mean just set the position of the playlist, use:
playlist.position = x
play
roytam1
30th March 2005, 05:16
I should a more clear about my question.
I want to enqueue a entry of current playlist. e.g. I want to enqueue No. 30 then I can use playlist(30).enqueue to enqueue it.
shaneh
30th March 2005, 06:15
I am still unclear what you mean. playlist(30).enqueue works as expected for me.
The playlist item number 30 is enqueued to the end of the playlist.
Maybe you are referring to 'enqueuing' in jtfe or something? That is not how winamp works normally. The playlist... is your playlist. Enqueing an item enqueues it to the playlist.
What do you want to happen when you call:
playlist(30).enqueue?
Do you want the item to play? Do you want the item to be enqueued to the end of the playlist?
If you want the item to be the next item to play, that is not how winamp works. To handle that, handle the song change event and set the playlist position manually. Or use the JTFE API to set the next item, if it has one that does that.
antu^jamban
1st April 2005, 10:31
Thanks for the info shaneh.
antu^jamban
8th April 2005, 15:30
If I understand you clearly, all the info is gathered from ML. What if a person have ML removed or not installed? So we can't get any info rite?
saivert
8th April 2005, 16:28
I really don't understand why JTFE was born at all. The way I see it, enqueue means to put things at the end of the playlist. The playlist is essentially a queue to me.
But people like it to be a song list instead so then JTFE was invented to step in inbetween.
DrO said he was going to implement a JTFE API which would offer his own Playlist selection API too I guess.
Originally posted by saivert
I really don't understand why JTFE was born at all.since people like temporary playlists and don't want to mess up their main playlist order + it was a Winamp3 feature that people wanted
-daz
saivert
8th April 2005, 16:57
Well. I really pointed out that in my post too, if you read more closely. And I do know it was a Winamp3 feature.
@ShaneH: How long have you come in the development process for AW? Do you write a log? What's the next step?
vBulletin® v3.8.6, Copyright ©2000-2013, Jelsoft Enterprises Ltd.