|[ English | Español | Pyccκuú ]|
uFMOD is an XM player library written in assembly language. It's perfect for size- and speed-critical applications, click free, highly reliable, easy to use, open source, multiplatform. File, resources and direct memory playback supported. It is able to play even damaged and non-standard XM tracks. Usage examples available for the following compilers: Visual C++, C#, Visual Basic, PureBasic, FreeBASIC, BlitzMax, Emergence BASIC, Delphi, Borland C++ Builder, Dev-C++ (MingW), FreePascal, MASM32, FASM, NASM and TASM.
uFMOD for Win32 supports WINMM, DirectX® DirectSound and OpenAL. All three drivers have pros and cons. DirectSound provides sound effects, mixing capabilities and a wide range of advanced features, like 3D sound. It is even considered to be more reliable than WINMM. On the other hand, WINMM is almost always available, even in good old Windows 95. OpenAL is cross-platform (available in Windows, Linux, Macintosh, etc.), features hardware accelerated environmental effects, very useful in game development. However, it is not preinstalled in Windows XP and earlier, except in some OEM machines with high-end Creative sound cards. So, you'd probably need to download the redistributable OpenAL drivers prior to starting developing OpenAL-powered applications. Depending on hardware and drivers, WINMM output could sound clearer than DirectSound's or viceversa. However, most users won't tell the difference. If you are not sure which uFMOD version to choose for your project, probably the standard WINMM version whould suit your needs better. At least, it's easier to use: just a couple of lines of source code will do the job.
There are 2 freeware tools currently available to use along with uFMOD: XMStrip and Eff. Both utilities have dual interface: console and graphical (GUI). When ran with command line arguments, console mode is triggered. GUI is rather self-explanatory. Next, we'll explain console-based usage.
|SVN||Complete source code available|
XMStrip expects an XM filename on input, repacks the file contents to make it smaller, without losing sound quality. What it does exactly is removing overhead data (dummy instruments, patterns and junk metadata), stripping reserved and currently unused bytes, repacking pattern data. Typing
xmstrip /h produces the following output:
uFMOD XMSTRIP USAGE: xmstrip [options] file [output] file - input file name, which can contain wildcards (* and ?) for batch processing. output - optional output file name options: /c - clean only (don't strip) When [output] is not specified, XMSTRIP attempts to overwrite the input. If file name contains spaces, enclose it in "".
Keep in mind, that other XM players whould probably reject a 'stripped' XM file. The /c option is useful for 'recovering' such a stripped file or just cleaning a regular file intended to be played with any other XM player.
Eff is useful for advanced users, willing to squeeze every single byte out of their applications. The general idea is to extract only those features you do mean to use in your application, recompile the uFMOD library from source and obtain the smallest possible footprint. So, let's start opening the command shell and typing
eff /h to request the following prompt:
uFMOD XM effects extractor USAGE: eff [options] file file - input file name options: /Dm - generate a masm32/tasm dump /Dd - generate a Pascal (Delphi) dump /Dc - generate a C/C++ dump /Ds - generate an RCDATA resource dump /Di - disable infoAPI: uFMOD_GetStats, uFMOD_GetRowOrder, uFMOD_GetTitle and uFMOD_GetTime /Dp - disable uFMOD_Pause, uFMOD_Resume and XM_SUSPENDED /Dv - disable volume control /Dj - disable Jump2Pattern /Df - disable loading XM from file /Dr - disable loading XM from resource /Dl - disable XM_NOLOOP /M - mark & clear unused chunks of data in a masm32/tasm compatible dump
As you can see, the last parameter is expected to be a filename, specifying the XM file you plan to use in your application. Additional options:
id RCDATA "filename"syntax. An RCDATA hex dump should be used for compatibility with early GNU resource compilers, like the one included in Dev-C++.
eff /Dmpvjfrl /M example.xm
eff /M /Dm /Dp /Dv /Dj /Df /Dr /Dl example.xm
eff -M -Dmpvjfrl example.xm
The above commands produce a MASM32/TASM dump with all the 'holes' properly outlined and cleared by default. The EFF.INC header contains the XM effects actually used in the given XM file and some additional flags to disable pause/resume, volume control, Jump2Pattern, file and resource support and XM_NOLOOP. Copy EFF.INC to ufmodlib\src\ and recompile the library (check the following section for a quick guide). Enjoy your own extremely optimized uFMOD build, but keep in mind that it contains a subset of XM effects. So, it will play normally only the given XM file!
Recompiling the library sources is required after using Eff or to enable some special features in a regular build (check the Options table below). Some people might consider modifying the source code of the library just to practice assembly programming or for any other reason. Well, the following information is intended only for those interested in the subject.
The complete source code is included in ufmodlib\src\:
There's a tool available in ufmodlib\bin\. It is used to make a regular OMF object file compatible with Delphi. It's not as powerful as EliCZ' OMF2D, but smart enough to make a Delphi compatible uFMOD library. When building uFMOD in OMF format with NASM, o4delphi gets involved.
|SVN||Complete source code available|
Once you are done modifying the uFMOD sources, next step is compiling them. Pick one of the batch files located in ufmodlib\ depending on the target compiler you want to build uFMOD for. The following table should help you selecting the proper batch file:
|mk_coff||Visual C/C++, Dev-C++ (MingW), FASM, NASM, MASM32, FreeBASIC||The most recommended assembler for building uFMOD in COFF format is FASM.|
|mk_omf||Borland Delphi, Borland C++ Builder, TASM||Borland C++ Builder and TASM users should set UF_FMT option to LIB. Delphi users should set it to OBJ instead.|
|mk_vb6||Visual Basic 6|
Now open the selected batch file in a plain text editor. Everything contained between the following lines:
rem *** CONFIG STARTand
rem *** CONFIG ENDis configurable. First of all, check the
Pathessection. There might be an option saying:
SET UF_MASM=C:\masm32If you do have MASM32 installed, make sure the above path points exactly to where MASM32 is located. Let's say MASM32 has been installed to
D:\TOOLS\MASM32. Then, you'd have to modify the above entry as follows:
SET UF_MASM=D:\TOOLS\MASM32Not all of the pathes are always used to recompile the libraries. For example, if you prefer using FASM as your default assembler, you don't need to setup the MASM32 path. Some pathes contain filenames as well. For example:
SET UF_ARCH=arar.exe is supposed to be in one of the directories that are listed in the PATH environment variable. If not, you'd have to modify the above entry. Let's say
C:\Program files\BlitzMax\bin\ar.exeis the correct path. So, let's modify the UF_ARCH variable:
SET UF_ARCH=C:\Program files\BlitzMax\bin\ar.exeMake sure all the pathes actually required to build the libraries have been set correctly. Then, procede modifying the available options, according to the following table:
|UF_RAMP||This option controls the volume ramping (interpolation) mechanism. Ramping is intended to suppress audible clicks, but sometimes it may introduce distortion. STRONG is the default value recommended for most applications. It detects volume changes during sample playback and softens them using a 64 stage linear ramp. WEAK uses 16 linear stages only. It is less effective than STRONG, but distortion is also less likely to happen. NONE doesn't perform ramping at all. No ramping = no distortion, but most XM samples will produce clicks, unless the samples are well balanced enough.||NONE, WEAK, STRONG|
|UF_FREQ||Mixing rate (in Hz). 44100 was the default value until uFMOD v1.20. 48KHz actually sounds better on most soundcards and uses less system resources. So, 48000 is the new default value recommended for most applications. 22050 is supported just for fun (rememder the Amiga days...)||22050, 44100, 48000|
|UF_UFS||Text encoding. Unicode applications should set this to UNICODE, except in BlitzMax, PureBasic and Visual Basic 6, where UNICODE option is not currently supported. Keep in mind that Unicode applications run significantly faster on NT/XP machines. UNICODE is mandatory when recompiling uFMOD for .NET.||ANSI, UNICODE|
|UF_FMT||Produce a set of static libraries, plain object files or DLLs and import libraries. For example, Delphi doesn't support lib-files, so you should set UF_FMT to OBJ for Delphi compatibility. C/C++ and all of the assembler compilers support both libs and objs. Some compilers don't support static linking at all, so DLL is the only way to go. It defeats the whole point of using XM music though. We've included this option for the sake of completeness only.||OBJ, LIB, DLL|
|UF_ASM||Assembler. Yes, the uFMOD libraries are compilable with various assemblers. Choose your favorite :)||MASM, NASM, FASM, TASM|
|UF_MODE||NORMAL is the default value. Nothing special. UNSAFE disables checking an XM track for validity at load time. When you are sure all XM tracks are valid (you can use Eff or XMStrip to verify an XM file), you can recompile uFMOD in UNSAFE mode to reduce the file size and maximize the loading speed. Keep in mind that a damaged XM file can actually crash uFMOD while in UNSAFE mode! Recompiling uFMOD in BENCHMARK mode makes available a performance counter, which tells the exact amount of clock cycles used to produce about 21 ms of sound @ 48KHz. This mode is meant to be used for comparing the performance of different uFMOD versions. Check the C examples and the BENCHMARK flag for more info. BENCHMARK mode is available only in C, MASM, FASM, NASM and TASM.||NORMAL, UNSAFE, BENCHMARK|
Run the batch to build all the available library targets: WINMM, OpenAL and DirectX DirectSound. That's all!
Compiler-specific usage examples are provided in separate folders. Every example folder contains WINMM and DirectX projects. OpenAL examples are available for most of the compilers as well. Most representative examples contain prebuild executables to show the smallest image size achieved so far. Prebuilt binaries are neither compressed, nor packed.
|BCB||Borland C++ Builder||dododo|
|Delphi||Borland Delphi||*||Delphi 5 - 7 users should compile the examples via the batch files in order to make the executables a bit smaller. Delphi 9 or later users should build both projects from the IDE only, because some compiler internals used in the BATs changed in later versions.|
Complete and up-to-date DirectSound and OpenAL units for Delphi are available. uFMOD for DirectX DirectSound and OpenAL require these units. You can also use them in stand alone projects.
|Fasm||Flat Assembler||bogrus, *||Pure FASM (no linker) and FASM plus MS Linker or Polink examples provided just to show both ways to build an executable using FASM.|
|Masm32||MASM32||*||The most complex uFMOD usage samples. The main idea is to place the executable code and data inside (!) the XM stream to reduce the executable image size. Only for real optimization freaks! RadASM IDE project files included.|
|Nasm||Netwide Assembler||*||Using MS Linker or Polink.|
|Tasm||Borland Turbo Assembler||*||RadASM IDE project files included.|
|PureBasic||PureBasic||flaith, chris_b||PureBasic version 3.50 or later required. Copy the given PureLibraries to [PureBasic]\PureLibraries\UserLibraries before compiling the projects. A helpfile for PureBasic uFMOD API is available in the HELP subfolder. Copy this CHM to [PureBasic]\HELP if you wish to use it from the IDE.|
The OpenAL example require the PureBasic OpenAL SDK, which can be found at the ImpLib SDK website.
|VisualBasic6||Visual Basic 6||*||Read the readme file before compiling!|
|C||Visual C/C++, Dev-C++||*||Minimalistic XM players written in plain C. Load / stop, pause / resume, muting, volume control, playback progress, VU meter, drag&drop and even some DX effects in 15Kb! Both examples support Unicode and the special BENCHMARK mode (requires recompiling the library in BENCHMARK mode first). Tested with Visual C++ 6.0, Visual C++ 2005/2008 Express Edition and Dev-C++ 188.8.131.52.|
An example showing how to use the Jump2Pattern feature is also available here. It uses a composite XM tracked by Kim (aka norki). For more information on composite XM files and the Jump2Pattern feature, refer to the following section.
There is a dynamic OpenAL example here as well - it will run even when OpenAL DLL is not found.
|BlitzMax||BlitzMax||*, flaith||Complete documentation provided.|
Complete and up-to-date DirectSound and OpenAL modules for BlitzMax are available. uFMOD for DirectX DirectSound and OpenAL require these modules. You can also use them in stand alone projects.
|FreeBASIC||FreeBASIC||voodooattack, antarman||Using a visualization based on Torus by rel. FbEdit IDE project files included.|
|FreePascal||FreePascal||*||Tested with FPC v2.0.4.|
Complete and up-to-date DirectSound and OpenAL units for FreePascal are available. uFMOD for DirectX DirectSound and OpenAL require these units. You can also use them in stand alone projects.
|C#||.NET SDK||*||A set of C# examples tested with .NET Framework 2.0. Featuring standalone EXE projects using mixed CLI/C++ code. To make the uFMOD API available in .NET we've made a C++ wrapper to serve as a bridge between managed and unmanaged code. The complete source code is included.|
Use Eff to optimize the library and make it smaller.
When embedding the XM track directly into the executable or attaching it as a raw binary resource, it's sometimes worth it trying to optimize the XM itself. Modplug Player features ADPCM compression, which makes the XM somewhat smaller, but it's a lossy compression! Use XMStrip for lossless (in terms of sound quality) size optimization.
If you're sure all XM tracks your application is going to use are valid (not damaged or otherwise modified), rebuild the library in UNSAFE mode.
Try using the undocumented directive
/opt:nowin98 while linking a Visual C++ or MASM32 project to minimize section alignment. The .rdata section (read-only data, where the IAT and some other constants reside) and .text section (usually contains executable code) could be safely combined together into a single section. Try adding the following directives to MS LINK.EXE or POLINK.EXE command line:
There's another MS linker-specific known issue. link.exe attaches some unnecessary data between DOS stub and the beginning of PE header. It's easy to spot the dead weight in a Hex editor - it begins with a magic word 'Rich'. The encoded machine compid follows the magic word. If you don't want your executables being signed this way or just don't like to spend some extra bytes (actually, it's half a Kb!) on the signature, there's a couple of workarounds available. First, you can switch to another linker. Or you can search the web to find an article on patching link.exe. Psst! It's written in russian and available somewhere at wasm.ru.
Delphi likes to include a Relocation Table (.reloc section) inside every single executable. That's not required for a typical exe to run (but not a DLL!) and you may safely remove that section. Try using StripReloc by Jordan Russel, PE Optimizer by Dr. Golova or a similar tool in case you don't know how to remove relocations by hand.
Visual Basic and Delphi like to create a Resources section (.rsrc) even if it doesn't contain any useful resources. So, it's usually safe to remove the whole resources section if it doesn't contain forms, XMs or anything your program might really need. The same applies to .flat sections inside PureBasic executables. Be careful while performing this kind of operation on your exe!
When using MS-COFF import libraries (like kernel32.lib, libkernel32.a, etc.) some space is wasted in the executable image to hold the original thunks tables. These tables are only required when binding the executable image. If you don't plan to bind your executables, you can get rid of the original thunks and save up to 512 bytes or even a couple of kilobytes when importing a large amount of symbols. To do so you should replace the original import libraries, shipped with your compiler SDK (Visual Studio, masm32, etc.) whith modified (stripped) import libraries and rebuild your projects. You can make a "stripped" import library with ImpLib SDK.
That's pretty much everything one should know about optimizing an executable file for size. Let's talk some more about optimizing the XM file size:
An advanced XM file size optimization method involves merging various XM tracks in a single composite file. Since you can share the instruments in a composite file, the resulting file size could be a lot smaller than the sum of the separate file sizes before merging. Even without sharing the instruments it will be smaller because of the XM file header being declared only once. Let's see an example with 3 XM files:
File 1 : XM1_HEADER P11 P12 P13 I11 I12 File 2 : XM2_HEADER P21 P22 P23 P24 I21 I22 I23 I24 File 3 : XM3_HEADER P31 I31Legend: XMn_HEADER is the header of the n-th XM file. Pni is the i-th pattern of the n-th XM file. Ini is the i-th instrument of the n-th XM file.
First, let's merge them in a single file without sharing the instruments:
File 4 : XM4_HEADER P11 P12 P13 P21 P22 P23 P24 P31 I11 I12 I21 I22 I23 I24 I31Now, let's say I12 is very similar or even equal to I23 and I24 is the same as I31. So, we can modify P2n to make them use I12 instead of I23 and P31 to use I24, so that we can remove I23 and I31:
File 4 : XM4_HEADER P11 P12 P13 P21 P22 P23 P24 P31 I11 I12 I21 I22 I24You'll have to modify the looping and pattern jumping commands and the references to instruments in "files" 2 and 3. Obviously, you can merge just 2 files or more than 3. XM file format limits the amount of patterns and instruments in a single file. That's the general idea. You'd have to learn how to use a tracker in order to perform this kind of optimization. Once you've got all your files merged, you can issue a single uFMOD_PlaySong function call and trigger all the "files" with uFMOD_Jump2Pattern. For example, uFMOD_Jump2Pattern(3) will start playing the 2nd "file", uFMOD_Jump2Pattern(7) will launch the 3rd and uFMOD_Jump2Pattern(0) will reset to the first "file". The exact indexes depend on your pattern layout. C\WINMM\ contains a practical example.
Using Jump2Pattern has another advantage: switching is done much faster (practically in no time), as opposed to stopping and reloading a track. So, you can use this feature when quickly switching the background music is required.
Q: Is uFMOD free for any type of use? Even commercial?
A: Yes, currently it is.
Q: Where can I get XM files from?
A: Try visiting The Mod Archive. They have a huge archive of free tracker music in XM, IT, S3M and MOD format. You can use Open Modplug Tracker to convert IT, S3M and MOD tracks to XM format without apparent degradation. There are many talented composers out there in the web sharing their music at no cost. Just don't forget the copyright!
Q: Is uFMOD related in some way to Firelight Technologies® FMOD and miniFMOD sound libraries?
A: Not any more. Up until 2004 uFMOD was based on the latest miniFMOD public source code release. Since then, library sources had been completely rewritten, introducing many new features. So, uFMOD is in no way representative of FMOD and miniFMOD sources.
Q: Some XM player libraries claim to add only N kilobytes to the executable file. How many Kb does uFMOD add exactly to the executable's size?
A: It is impossible to tell an exact value, because it depends on library features used (especially, when using the Eff utility), test program code layout, XM file size (when embedding the XM into the EXE). It also depends on the linker options. For example, MASM32\minimal.exe is 5.632 bytes without compression, PE format hacking or any other dirty size optimization tricks.
Q: Where can I get the official XM file format specification from?
A: No official and up to date specification exists. However, you can take a look at "The Unofficial XM File Format Specification: FastTracker II, ADPCM and Stripped Module Subformats". This document covers most aspects of the original XM file format and all the non-standard extensions currently supported by uFMOD. ModePlug's public source code (it's C++) also serves as reference material on module file formats.
antarman, Barracuda, bogrus, chris_b, cresta, dododo, flaith, Four-F, GL#0M, norki, q_q, SofT MANiAC, S_T_A_S_, ts-soft, voodooattack and yoxola for reporting bugs, requesting interesting features, submitting usage examples and otherwise helping us improve uFMOD.
uFMOD sources, binaries and utility programs © 2005 - 2008 Asterix and Quantum.
All rights reserved.
|Found a bug? Got a question or a suggestion?|
Starting to develop a cool application using uFMOD? Please, let us know: firstname.lastname@example.org