Author Topic: DSP Plugin API, GetConfig, Thread saftey  (Read 257 times)

Utedass

  • Posts: 3
DSP Plugin API, GetConfig, Thread saftey
« on: 26 Jan '19 - 15:34 »
Hello!
This is my first post here, please treat me well :)

I am new to plugin programming for XMPlay.  I want to make a physical control panel for displaying and changing user rating, so I decided to learn how to make a general plugin using the DSP plugin header.

Is the purpose of SetConfig and GetConfig for me to store and retrieve my own data, or rather some special data meant to interact with XMPlay in some way?
These are the function I currently am most confused about. Of course I have checked the example plugins supplied with the plugin api, but I still don't feel comfortable using them.

I noticed that the data I store and retrieve is appended to the DSP rown in xmplay.ini

Also I want to know a correct way of using the GetConfig function. The flage plugin supplied with the plugin API does this:

Code: [Select]
static DWORD WINAPI DSP_GetConfig(void *inst, void *config)
{
FlangeStuff *flange=(FlangeStuff*)inst;
memcpy(config,&flange->conf,sizeof(flange->conf));
return sizeof(*flange); // return size of config info
}

How can this ensure that there is enough memory allocated at config, considering that the memcpy occures before DSP_GetConfig returns the size of the data stored to the caller?
Is there a size limit of the data to store stated somewhere, that we are supposed to not exceed?

I will probably not need to store much data for my plugin, and I might end up giving it its own config file, but I am still curious about the intended usage of these functions.

Is the misc function for sending DDE commands is thead-safe?
That is the function I know that I want to use from a thread on its own. Are there any functions in the plugin that are not thread-safe?

Is there a documentation for the plugin API other that the comments in the code?
I searched a lot but my google-fuu might just not be good enough to find it.. :p

Are there any known tutorials around for writing plugins for XMPlay?
As a beginner I found it difficult to setup my project to work correctly as there seems to be some difference in my environment compared to the one used to make the examples provided with the API.
The most difficult for me was to realize that the XMPDSP_GetInterface2 was name mangled and not exported correctly with the provided code, but I had to add extern "C" to the declaration.
If there isn't a tutorial available, maybe I could take some time to make one in the future for other beginners to find :)


That's all for now, thanks for a great music player! <3  ;D

Ian @ un4seen

  • Administrator
  • Posts: 21539
Re: DSP Plugin API, GetConfig, Thread saftey
« Reply #1 on: 28 Jan '19 - 18:05 »
Is the purpose of SetConfig and GetConfig for me to store and retrieve my own data, or rather some special data meant to interact with XMPlay in some way?

XMPDSP:GetConfig/SetConfig are called by XMPlay to get/set your plugin instance's config. Each instance in the "DSP and general plugins" list has its own config. If you have global settings that apply to all instances, you can use the XMPFUNC_REGISTRY functions for that instead.

Also I want to know a correct way of using the GetConfig function. The flage plugin supplied with the plugin API does this:

Code: [Select]
static DWORD WINAPI DSP_GetConfig(void *inst, void *config)
{
FlangeStuff *flange=(FlangeStuff*)inst;
memcpy(config,&flange->conf,sizeof(flange->conf));
return sizeof(*flange); // return size of config info
}

How can this ensure that there is enough memory allocated at config, considering that the memcpy occures before DSP_GetConfig returns the size of the data stored to the caller?
Is there a size limit of the data to store stated somewhere, that we are supposed to not exceed?

The size of the config data should not exceed 16KB.

Is the misc function for sending DDE commands is thead-safe?
That is the function I know that I want to use from a thread on its own. Are there any functions in the plugin that are not thread-safe?

ExecDDE should be thread-safe. The rest should generally be too but it's possible that some stuff isn't. Let me know if you do encounter any such problems.

Is there a documentation for the plugin API other that the comments in the code?
I searched a lot but my google-fuu might just not be good enough to find it.. :p

Unfortunately not, but if anything is unclear, you can post your questions here.

Are there any known tutorials around for writing plugins for XMPlay?
As a beginner I found it difficult to setup my project to work correctly as there seems to be some difference in my environment compared to the one used to make the examples provided with the API.
The most difficult for me was to realize that the XMPDSP_GetInterface2 was name mangled and not exported correctly with the provided code, but I had to add extern "C" to the declaration.
If there isn't a tutorial available, maybe I could take some time to make one in the future for other beginners to find :)

It is probably about time that the example projects were updated to a bit more modern version of Visual Studio! I will look into that this week.

Ian @ un4seen

  • Administrator
  • Posts: 21539
Re: DSP Plugin API, GetConfig, Thread saftey
« Reply #2 on: 30 Jan '19 - 15:07 »
Updated projects for the examples have now been added to the XMPlay plugin SDK package.

Utedass

  • Posts: 3
Re: DSP Plugin API, GetConfig, Thread saftey
« Reply #3 on: 31 Jan '19 - 10:51 »
Thank you very much for your reply and the swift actions!

This kind of service really makes me like XMPlay. I have been browsing through the forum and I am so impressed by your support! Kudos!

I realize now that I left out a detail about "my environment" in my original question. I am using CodeBlocks with MinGW GCCcompiler. But I managed to compile a proper DLL and learned a lot along the way, so that is not a bad thing :)

This is the prototype I use to make it work (for any other MinGW GCC user to find):

extern "C" XMPDSP * __declspec(dllexport) XMPDSP_GetInterface2(DWORD face, InterfaceProc faceproc)
Edit: It might be unwise to use the above statement. A friend of mine pointed out that it will probably use the wrong calling convention. I'll look into how to make it in a proper way when I have time.

It seems that MSVC and GCC treats exports to DLLs differently. Also it doesn't seem to be an easy way of utilizing the provided .def file with GCC to specify the exported names, and I guess this is what prevents c++ name mangling when using MSVC. It seems using extern "C" is enough to export XMPDSP_GetInterface2, and the __declspec(dllexport) seems to get rid some other unnecessary exports, which i don't really know where they come from..

Well, I am totally not sure about the details, but it gets the job done! I checked the DLLs using nirsofts dll export viewer to get a hunch of what is happening.

Thanks again for superb support!
« Last Edit: 1 Feb '19 - 13:15 by Utedass »

Ian @ un4seen

  • Administrator
  • Posts: 21539
Re: DSP Plugin API, GetConfig, Thread saftey
« Reply #4 on: 1 Feb '19 - 16:40 »
Yeah, when using C++, extern "C" will be needed on the plugin's exported function(s) when using Mingw. I've added that to the examples now.

extern "C" XMPDSP * __declspec(dllexport) XMPDSP_GetInterface2(DWORD face, InterfaceProc faceproc)
Edit: It might be unwise to use the above statement. A friend of mine pointed out that it will probably use the wrong calling convention. I'll look into how to make it in a proper way when I have time.

I think that should be fine so long as you keep "WINAPI" in there:

Code: [Select]
extern "C" __declspec(dllexport) XMPDSP* WINAPI XMPDSP_GetInterface2(DWORD face, InterfaceProc faceproc)

Regarding using a DEF file with Mingw, simply including it in the linker command-line/options should work.

Utedass

  • Posts: 3
Re: DSP Plugin API, GetConfig, Thread saftey
« Reply #5 on: 2 Feb '19 - 20:11 »
Yes, WINAPI evaluates to __stdcall, and thus the stack cleanup is handled by the callee.

The problem now is that the default way for GCC and its linker is to export the function as "XMPDSP_GetInterface2@8", that is adding decoration telling the number of argument.
This decoration can be removed by passing "-Wl,--kill-at" to the compiler. Or only "--kill-at" if you pass it directly to the linker.

I fiddled around a bit more with the DEF file, and you're right, the only thing needed for using it was passing the name to the linker. For me that becomes "-Wl,xmpdsp.def". This is, however, not necessary if using the "__declspec(dllexport)" in combination with the "--kill-at" flag.

I found lots of information on the subject at the following address: http://www.willus.com/mingw/yongweiwu_stdcall.html

So the two ways I now know of doing it right, using Code::Blocks with MinGW, are:
Code: [Select]
Alt.1
// Linker flags: -Wl,--kill-at
extern "C" XMPDSP* __declspec(dllexport) WINAPI XMPDSP_GetInterface2(DWORD face, InterfaceProc faceproc)

Alt.2
// Linker flags: -Wl,xmpdsp.def
extern "C" XMPDSP* WINAPI XMPDSP_GetInterface2(DWORD face, InterfaceProc faceproc)

For me, the second alternative generates a warning: "Warning: resolving _XMPDSP_GetInterface2 by linking to _XMPDSP_GetInterface2@8" but it seems to work fine.

I hope this is correct and work for others as well :)

Thanks for the help Ian, really appreciated!