Blitz PLus module player?

Miscellaneous Forums/General Discussion/Blitz PLus module player?

Does anyone have a separate module player for Blitz Plus?

OK, I know Blitz plus has a built in module player, but there are two problems I find with it. One is that certain modules sound clicky when the Note Off (Key Up) is used. These modules are fine in MadTracker or Modplug player for example.

And 2nd, I would really like a player that stores the state of each channel in a user-accessible area of memory. This way you can tell which note is currently being played on each channel. For the Amiga I found some assembly source for a module player and put my own extra bits in so that every time a note was played in a channel it stored a value in the memory. Then I could Peek (read) the memory with my app (demo) and show equalisers for each channel/note instead of just for the overall sound (which is what most visualisations do today). This was really cool at the time and I'd love to do it again, so any help? Maybe there is an open source module player as a .dll that can be interfaced with?

There's D.U.M.B. but you would have to write a sound server for it and compile a dll yourself. Then there are FMOD and BASS (free for non-commercial exploits) which are both ripe for either the .decls or CallDll treatment.

hmm, ok thanks. Anyone else got anything easier? I'm feelin lazy.

That's about as easy as it gets I'm afraid. The functionality you want would be external to Blitz so you can't really avoid having to either write a "bridge" dll (for CallDll) or knuckle down and define a .decls file (for more fully integrated variable passing).

Incidentally, if you ever see an example of the Modplug playback library being used give us a heads up - nobody seems to know how to implement it. :/

OK, thanks, roger wilco.

[edit] found the Modplug SDK here http://www.castlex.com/modplug/developer.php3?session=
the .h file isn't much use yet. The webpage above has the C .dll functions. These need to be added to a .decls file in the correct blitz format which I'm not very good at. Then I guess you just need to call ModPlug_Load. Not sure if you need to call ModPlug_Create first and ModPlug_Destroy later? Actually based on the parameters of Modplug_load, I'd say you DO need to make a plugin first)

[edit] made the following .decls file .lib "mppsdk.dll"
ModPlug_CreateEx%(lpszArgs$):ModPlug_CreateEx
ModPlug_Destroy%(pPlugin%):ModPlug_Destroy
ModPlug_Load%(pPlugin%, lpszFileName$):ModPlug_Load

but when compiled and running I get a "user lib function not found" error when the ModPlug_CreateEx("") function is called. I checked the mppsdk.dll in notepad and the functions aren't in it? Maybe they're in another .dll or I;m missing something?

Thanks - I don't think there was an example showing usage in those files and nobody on the forum seemed any the wiser about the issue last time I investigated. I'm a bit more experienced now, though, so I'll maybe have another look. If I get anywhere I'll let you know.

The reason the Modplug library would be useful, by the way, is that the Modplug .IT standard (in particular) isn't (standard). So if you use Modplug Tracker to make .it tunes it's handy to have that specific replay library available to your apps.

I found out I was using the wrong dll, I downloaded the plugin and got out npmod32.dll. Now the function is detected and works but the ModPlug_Load function's result, which is supposed to be boolean, is always 0. I'm calling it like this
ModPlug = ModPlug_CreateEx("loop|true|vucolor|#ff00ff|")
		Notify ModPlug
		sp$ = "c:\test.xm"		
		Local test = ModPlug_Load(ModPlug, sp)		
		Notify test
		test2 = modplug_play(ModPlug)
		Notify test2

Note that modplug is a valid value it's just that the loading fails. I am passing in a string and wonder if this is correct, perhaps it needs an area of memory fomatted to look like a c string and wants a pointer to that memory. Know how to do that? I though the strings in blitz were c strings but maybe they are not. The sdk help says this is the C declaration BOOL WINAPI ModPlug_Load(LPVOID pPlugin, LPCSTR lpszFileName), so maybe I have misinterpreted LPCSTR lpszFileName as a string instead of a pointer.

Anyway I gotta go to bed now. I wish this worked... sigh.

OK, I added this to the .decls file
ModPlug_SetWindow%(pPlugin%, hwnd%):ModPlug_SetWindow

then called
TheWindow = User32_FindWindowA("",FULLNAME)		
		Local test0 = ModPlug_SetWindow(ModPlug, TheWindow)

and it works! It adds a mod plug equaliser to the window which I don't want, I guess there must be parameters to turn stuff on/off.

It plays quiter than blitz but without clicks of note ups which is great! And I guess it supports loads of formats too.

To summarise made a .decls file
.lib "npmod32.dll"

ModPlug_CreateEx%(lpszArgs%):ModPlug_CreateEx
ModPlug_SetWindow%(pPlugin%, hwnd%):ModPlug_SetWindow
ModPlug_Destroy%(pPlugin%):ModPlug_Destroy
ModPlug_Load%(pPlugin%, lpszFileName$):ModPlug_Load
ModPlug_Play%(pPlugin%):ModPlug_Play


then call this code
Global ModPlug

ModPlug = ModPlug_CreateEx("loop|true|vucolor|#ff00ff|")		
TheWindow = User32_FindWindowA("",FULLNAME)		
ModPlug_SetWindow(ModPlug, TheWindow)		
sp$ = "c:\music1.xm"		
ModPlug_Load(ModPlug, sp)				
ModPlug_Play(ModPlug)		


and later on call ModPlug_Destroy(ModPlug)

[edit] just noticed that when you reload the game, the module resumes play from where it last left off, this is odd! I guess it needs another command line param or a function call to reset it each time.

EDITED : The old post doesn't really apply now that you've solved it - top work!

Re the window stuff (below), yeah I noticed that in the commands list and crossed my fingers that it wouldn't open a window... odd to make a sound library that does that. :-/

I'll check the others out soemtime. Basically it works now, it's just that I don't want to have the modplug equaliser graphics in my game window! There must be a way to switch this off, perhaps via command line params but I don't know what they are or how to find out. The other issue is the the module starts playing from where it left off instead of the start, this is odd.


The other issue is the the module starts playing from where it left off instead of the start, this is odd.



I added...
ModPlug_SetCurrentPosition%(pPlugin%, nPos%)

to the .decls file and...
ModPlug_SetCurrentPosition(ModPlug, 0)

...to the Blitz code just before starting to play the track.

By the way, for B3D ( I don't have B+) it's a little different to initialise (ta Sarge):
AppTitle "test" 
Global ModPlug

ModPlug = ModPlug_CreateEx("loop|true|vucolor|#ff00ff|")		
TheWindow =  api_FindWindow("Blitz Runtime Class", "test")
ModPlug_SetWindow(ModPlug,TheWindow)		
sp$ = "an-path.xm"		
ModPlug_Load(ModPlug, sp)
ModPlug_SetCurrentPosition(ModPlug, 0)				
ModPlug_Play(ModPlug)
WaitKey
ModPlug_Destroy(ModPlug)


Nice one Sledge! I was just too tired last night. btw I have an-path.xm too, it's a good one! Now all I have to find out is how to hide the equalizers.

You know at the start of the thread I was talking about making my own equalizers, well I wonder if the object pointed at by ModPlug has any integers than can be read (peeked) that correspond to the current note playing etc. Problems is finding them out would be pure guesswork.

I also added ModPlug_SetVolume%(plugin%, vol%):ModPlug_SetVolume so I can call it with 100 however, it seems to be on max volume by default. The weird thing is that it plays quieter than Blitz playmodule does and quieter than the actual modplug program and mad tracker too!

Okay, there is a further problem in the .decls file in that ModPlug_CreateEx%(lpszArgs%) should be ModPlug_CreateEx%(lpszArgs$)

With this change you can pass across the argument hidden|True - however this will hide the window you nominated for drawing so you should probably try to point the plugin to a dummy. Can the user32 lib create a new window? I hadn't touched it until this thread [goes off to look].

Yeah sorry about CreateEx, I turned it into a % (from $) just to test something, and forgot to put it back. Yeah you can create a new window with user32.dll.

Yep, hides my window too. Wow, theres nothing on the task bar and I can't alt tab it! or ctrl+alt+del as an app. Had to close blitzcc.exe in processes!

this works: User32_ShowWindow(TheWindow,1) call after the module is initialized and it will reshow you window. Needs to go in User32.decls. But some of modplug still seems to be showing.

The problem is that this .dll is a plugin not a pure music playing .dll. The fact that you have to create the plugin before playing anything is a bummer.

Where did you get the hidden|true command from? Maybe there are others?

I spose one of of should bung this in code archives when it's done.


Where did you get the hidden|true command from? Maybe there are others?



There was a readMe file in the plugin installer zip (npmod191.zip) that I downloaded. The bit concerning commands reads:


The other options you may want to add are the following:
- volume="x": set the volume of the song to x.
(Default="100", range="1" to "100")

- loop="true": Loop the song. (Default:"false")

- autostart="true": Start playing the song when loaded.
(Default="false"). (Also "autoplay" on versions 1.31+)

- autonext="true": Jump to next mod when finished playing.
(Default="false") This is useful only if you have more
than one song in your page. (You should use loop="true"
instead to make the same song loop)

- controls="none"/"stereo":
* "none": don't display anything - use with care
because there is no way the user will be able to stop the
mod (besides exiting the page). (same as "hidden="true")
* "stereo"(1.65+): the horizontal spectrum analyzer will
be split for right/left, on each side of the plugin.
In this case the number of bands will be (width - 184) / 16.
NOTE (1.75+): The option controls="smallconsole" has been
removed, it's now automatic if height < 20.

- hidden="true": same as controls="none".

- title="song_title": Displays the text "song_title" when
the song is not yet loaded. (Default: displays "Loading...")

- shuffle="true" (1.57+): goes along with autonext="true".
when a song finishes playing, the next song will be randomly
chosen. The shuffle option is a global flag and should appear
on the first EMBED section in the page. This flags sets
the autonext="true" flag automatically.

- bgcolor="black"(default),"gray" (1.60+): Select a background color
for the plugin.
v1.75+: you can specify a color like bgcolor="#RRGGBB".

- spcolor="red"(default),"green","blue" (1.61+): Select the color of
the spectrum analyzer.
v1.75+: you can specify a color like spcolor="#RRGGBB".

- vucolor="color1", vucolorhi="color2" (1.75+): you can now change
the color of the VU-meter. The default for vucolor is green, and
is red for vucolorhi.

- spcolorhi: defines the top-color of the spectrum analyzer (1.75+).
The default color is red. The middle color will be the mix between
spcolor and spcolorhi.

NOTE: (v1.43+)
--------------
- If you want to enable the VU-Meter, the width parameter
should be set to "168". The VU-Meter cannot be used with
the controls="smallconsole" option.
- If the plugin is hidden (with controls="none" or hidden commands),
autostart will be set to "true".

Spectrum Analyzer (1.60+)
-------------------------
- You can enable the spectrum analyzer by setting a height
of 96 (bottom spectrum) or a width of 336 (right spectrum).
- v1.61+: You can have from 3 to 80 bands in your right spectrum
analyzer: set the width parameter to 176+(numbands*8).
The frequency range is between 86Hz (left) and 11KHz (right).
- v1.65+: With the stereo spectrum, the number of bands on each
side will be (width - 184) / 16.





There's also a MPSNDSYS.H file in the sdk zip - I *guess* we're supposed to use that and the sdk dll (MPPSDK.DLL) for adding modplug playback to our own apps. Nobody on the forums seemed able to confirm when I looked, and a couple of people were asking.

For B3D I am pretty happy with this:

Graphics 800,600,0,2
SetBuffer BackBuffer()

AppTitle "test" 
Global ModPlug

ModPlug = ModPlug_CreateEx("loop|false|hidden|true")
TheWindow =  api_FindWindow("Blitz Runtime Class", "test")
ChildWindow=api_CreateMDIWindow% ("Blitz Runtime Class", "ModPlug Output", WS_MINIMIZE, 10, 10, 100, 100, TheWindow,0,0)
ModPlug_SetWindow(ModPlug,ChildWindow)		
sp$ = "an-path.xm"		
ModPlug_Load(ModPlug, sp)
ModPlug_SetCurrentPosition(ModPlug, 0)				
ModPlug_Play(ModPlug)

While Not KeyHit(1)
	Text 10,10,"ESC to quit."
	Flip
	Cls
	Delay 1	
Wend
ModPlug_Destroy(ModPlug)


Being a bit new to User32.dll, perhaps somebody can confirm that setting both hInstance% and lpParam* to zero (in CreateMDIWindow) is okay - it certainly seems so.

Okay, for B3D the following is pretty much everything:

modplug.decls
.lib "npmod32.dll"

ModPlug_CreateEx%(lpszArgs$)
ModPlug_SetWindow%(pPlugin%, hwnd%)
ModPlug_Destroy%(pPlugin%)
ModPlug_Load%(pPlugin%, lpszFileName$)
ModPlug_Play%(pPlugin%)
ModPlug_SetCurrentPosition%(pPlugin%, nPos%)
ModPlug_Stop%(pPlugin%)
ModPlug_IsPlaying%(plugin%)
ModPlug_GetCurrentPosition%(plugin%)
ModPlug_GetMaxPosition%(plugin%)
ModPlug_GetVolume%(plugin%)
ModPlug_SetVolume%(plugin%,vol%)
ModPlug_GetVersion%()
ModPlug_IsReady%(plugin%)



And an example of usage (dependent on npmod32.dll, modplug.decls & user32.decls remember):
Graphics 800,600,0,2
SetBuffer BackBuffer()

AppTitle "test" 

Global ModPlug

ModPlug = ModPlug_CreateEx("loop|true|hidden|true")
TheWindow =  api_FindWindow("Blitz Runtime Class", "test")
ChildWindow=api_CreateMDIWindow% ("Blitz Runtime Class", "ModPlug Output", WS_MINIMIZE, 10, 10, 100, 100, TheWindow,0,0)
ModPlug_SetWindow(ModPlug,ChildWindow)		
sp$ = "whatever.xm"		
ModPlug_Load(ModPlug, sp)
If Not ModPlug_IsReady(ModPlug) Then ModPlug_Destroy(ModPlug) : RuntimeError "Unable to initialise ModPlug :("
maxPos%=ModPlug_GetMaxPosition(ModPlug)
ModPlug_SetCurrentPosition(ModPlug, 0)				
ModPlug_Play(ModPlug)
ver%=ModPlug_GetVersion()

While Not KeyHit(1)
	If KeyHit(57)
		If ModPlug_IsPlaying(ModPlug)
			ModPlug_Stop(ModPlug)
		Else
			ModPlug_Play(ModPlug)
		EndIf 
	EndIf
	vol%=ModPlug_GetVolume(ModPlug)
	If KeyDown(12) And vol>0 Then ModPlug_SetVolume(ModPlug,vol-1)
	If KeyDown(13) And vol<100 Then ModPlug_SetVolume(ModPlug,vol+1)
	
	Text 10,10,"Using ModPlug Plugin Version "+ver
	Text 10,50,"ESC to quit,  SPACE to pause,  +/- to alter volume."
	Text 10,70,"Current Position: "+ModPlug_GetCurrentPosition(ModPlug)+"/"+maxPos
	Text 10,90,"Volume: "+vol
	Flip
	Cls
	Delay 1	
Wend
ModPlug_Destroy(ModPlug)


So hurrah, we can play mod music in Blitz again without having to use one of the commercial* API's - yay us!


EDIT: By way of notes, it's still a minor concern that the player seems to stay resident after an application quits, though as long as there's only one instance allowed I suppose it's *okaaaay*. Also, the version number returned seems way out (bleh!). Oh, and there's a twenty channel limit on the player so don't ask too much of it.

* The plug-in is only intended for non-commercial use so I guess you'd have to email the author, Olivier Lapicque (olivierl@...), if you wanted it for professional work. As the SDK is available for any purpose and we're essentially using the plugin in its place the response might be favourable - I should ask him, really. :D

OK good work! So hmm, 20 channel limit. Shouldn't be aprob in most cases. Can you get it to work without showing any contols at all then, as I have hidden the equalisers but the controls are still in my nominated window. I guess that's why you've made a minimised window. As I said, it would be best not to have to make a plugin in a window at all!

Bit worrisome that the player stays in memory after app quits! We should test for multiple instances just in case.

Still have the problem where it's not very loud, are you finding this?

Go on ask him. Maybe ask why it's not loud and how the .dll can be used without a visible plugin in a window. He may not answer ...

The Hidden|True parameter should nuke the window with the controls and equalisers (at least it does here*) - as you can probably tell from the bit of the ReadMe I posted, it's a web-browser plugin so, yes, it's a bit of a compromise. The SDK looks like it should offer the kind of core integration you're after, but it's written in C++ and I've a way to go before I fathom how to deal with it.

I'm assuming the player stays in memory due to its ability to continue playing from where it left off each time you run the app - that also suggests the same instance is operating each time, which is good.

I find it a *bit* quiet compared to BASSMOD (which is the cut down version of BASS... 34k DLL) but then I always switch on ramping and surround with that so it would be. The ModPlug SDK has a pre-amp function, access to which would be great.

I'll sound Olivier out if I can't find enough info to proceed elsewhere - someone on the ModPlug forum might have gotten somewhere since I last checked though.


*Okaaaay this is odd - I just tried to make a visible child window and still couldn't see anything! I guess I need someone with experience using user32.dll to comment on the window code because something is obviously awry.

The SDK is just a wrapper for the .dll that doesn't have core functionality like playing a module, it's only abouting mixing and stuff so basically it's useless for avoiding the whole plug in thing!

Hmm having said that maybe if the pre-amp function can be called via the SDK ...

You saw my code to show the current window right? User32_ShowWindow(TheWindow,1)


You saw my code to show the current window right? User32_ShowWindow(TheWindow,1)



Ah! It's clicked now... I didn't realise the Windows API did not show 'em by default so it was confusing me a bit as I was initialising ModPlug with hidden|false. If I ShowWindow the ChildWindow then up it pops as it should - always the silly little things that get you!

Shame about the SDK :(

Yeah, maybe I'll have to investigate a different one now as I want accurate playback and possible an interface so I can make my own equalisers (for a demo).