Making SoX into a working, usable DLL could be done rather quickly, but there would be a few tricky spots that any user of the DLL would have to watch out for. The primary changes would be to add a few accessor functions that return pointers to the SoX global variables (only functions can reasonably be exported from DLLs), and create a DEF file listing all of the functions that should be published from the DLL.
However, this DLL would be a bit tricky to use due to the following issues:
- Sox makes heavy use of global variables. Because of this, there could be only one client active in the application process, signficantly limiting the potential utility of the DLL.
- Sox exposes details of its C Runtime in its API via the FILE* exposed in the filetype structure and in providing lsx_realloc (and other related functions). If the client of the SoX DLL is using the same C Runtime library, these issues will go unnoticed, but if the client is using a different C Runtime library (MinGW instead of CygWin, or VC8 instead of VC9), exposing the internals of two C Runtimes to each other usually leads to bad results. Users of the DLL must not do any manipulation of the FILE* value except as provided by the lsx_* file manipulation functions. Users of the DLL must also use lsx_realloc(p, 0) to free any memory that was allocated via lsx_*alloc, and must not directly use free(p), since the user's free() probably comes from a CRT other than the one that was used to implement lsx_realloc. SoX needs to export a corresponding lsx_free, and all existing calls freeing memory allocated via lsx_realloc need to use lsx_free instead of the CRT free (since if you're in a DLL other than the SoX DLL, your CRT's free is likely not compatible with SoX's CRT's free.
In addition, the policy of lsx_realloc on failure to allocate memory is to exit the process. This is reasonable for a sox.exe command line, but is not a good solution for a library being hosted in another application. Instead, lsx_realloc needs to return a failure of some kind and the failure needs to be passed up the call stack with each routine freeing resources as the failure progresses up the chain. I suppose this sounds unlikely, but SoX could be considered very useful in embedded scenarios (cell phone music players) where memory runs out pretty quickly, and in that case, SoX shouldn't just crash whatever application it is running in.
Other minor issues is that there is an assumption in sox.c and other applications that sox.c would be compiled in the same envioronment and with the same settings as the rest of the sox library. In fact, the most logical first test of libsox.dll would be to create a sox.exe that assmes very little about the sox it communicates with, getting version numbers from the sox_version function instead of the PACKAGE_VERSION macro (since the DLL's version is the version we care most about), and getting other build information (like openmp support) from the DLL, not from macro definitions.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Making SoX into a working, usable DLL could be done rather quickly, but there would be a few tricky spots that any user of the DLL would have to watch out for. The primary changes would be to add a few accessor functions that return pointers to the SoX global variables (only functions can reasonably be exported from DLLs), and create a DEF file listing all of the functions that should be published from the DLL.
However, this DLL would be a bit tricky to use due to the following issues:
- Sox makes heavy use of global variables. Because of this, there could be only one client active in the application process, signficantly limiting the potential utility of the DLL.
- Sox exposes details of its C Runtime in its API via the FILE* exposed in the filetype structure and in providing lsx_realloc (and other related functions). If the client of the SoX DLL is using the same C Runtime library, these issues will go unnoticed, but if the client is using a different C Runtime library (MinGW instead of CygWin, or VC8 instead of VC9), exposing the internals of two C Runtimes to each other usually leads to bad results. Users of the DLL must not do any manipulation of the FILE* value except as provided by the lsx_* file manipulation functions. Users of the DLL must also use lsx_realloc(p, 0) to free any memory that was allocated via lsx_*alloc, and must not directly use free(p), since the user's free() probably comes from a CRT other than the one that was used to implement lsx_realloc. SoX needs to export a corresponding lsx_free, and all existing calls freeing memory allocated via lsx_realloc need to use lsx_free instead of the CRT free (since if you're in a DLL other than the SoX DLL, your CRT's free is likely not compatible with SoX's CRT's free.
In addition, the policy of lsx_realloc on failure to allocate memory is to exit the process. This is reasonable for a sox.exe command line, but is not a good solution for a library being hosted in another application. Instead, lsx_realloc needs to return a failure of some kind and the failure needs to be passed up the call stack with each routine freeing resources as the failure progresses up the chain. I suppose this sounds unlikely, but SoX could be considered very useful in embedded scenarios (cell phone music players) where memory runs out pretty quickly, and in that case, SoX shouldn't just crash whatever application it is running in.
Other minor issues is that there is an assumption in sox.c and other applications that sox.c would be compiled in the same envioronment and with the same settings as the rest of the sox library. In fact, the most logical first test of libsox.dll would be to create a sox.exe that assmes very little about the sox it communicates with, getting version numbers from the sox_version function instead of the PACKAGE_VERSION macro (since the DLL's version is the version we care most about), and getting other build information (like openmp support) from the DLL, not from macro definitions.