Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / MFC

Play XM in C++ - From File and Memory

4.90/5 (10 votes)
22 Oct 2010CPOL3 min read 31.6K   864  
Play XM music files in pure C++ using unpacked BASSMOD.dll from file and memory

Introduction

Some pepople like to play music in their applications. Generally, maybe because of size, people prefer .xm files and play them. Most cases are MFC and Win32. un4seen.com had coded BASSMOD.dll that can play them. This project uses this DLL without link to bassmod.lib.

Background

There are some code samples in the internet to do this, but this project has three good points that others don't:

  1. Their code uses bassmod.lib for linking the application to bassmod.dll. So, the coder cannot extract bassmod.dll from its resource and use it.
  2. Their code is so confusing and people cannot use it easily.
  3. bassmod.dll is packed using PEtite 2.2. This may casue some anti virus softwares; detect it as virus or suspicious file. Or maybe users get suspicious about it. I unpacked bassmod.dll successfully and you can use unpacked bassmod.dll in your project. Unpacked bassmod.dll is in package.

PEiD_4_bassmod.dll.jpg

Using the Code

You just need bassmod.dll to use this code (included in the package). For your convenience, copy the bassmod.dll to Windows directory.

When playing music reaches the end of music, it replays it. So, playing music is an infinite process that will never return. Since, I created I thread to play music.

C++
HANDLE hthread = CreateThread(NULL, NULL, MusicThread, NULL, NULL, NULL);  

If your project has a window (MFC or using CreateWindow), this code will work. But if your project is Win32, you should create another thread for your job and wait for it:

C++
WaitForSingleObject(hthread, INFINITE);
CloseHandle(hthread);

As this project doesn't link bassmod.dll to EXE, we should define function pointers that we need in run-time. The needed function pointers in bassmod.dll are:

C++
typedef int (__stdcall *func_BASSMOD_Init)(int device, int frequency, int flags);
func_BASSMOD_Init pBASSMOD_Init;

typedef int (__stdcall *func_BASSMOD_MusicLoad)
   (int mem, char *XMfile, int offset, int length, int flags);
func_BASSMOD_MusicLoad pBASSMOD_MusicLoad;

typedef int (__stdcall *func_BASSMOD_MusicSetSync)
   (int ptype, int param, void *function, int user);
func_BASSMOD_MusicSetSync pBASSMOD_MusicSetSync;

typedef int (__stdcall *func_BASSMOD_MusicPlay)();
func_BASSMOD_MusicPlay pBASSMOD_MusicPlay;

typedef int (__stdcall *func_BASSMOD_Free)();
func_BASSMOD_Free pBASSMOD_Free;

Needed function pointer in winmm.dll:

C++
typedef DWORD (__stdcall *func_timeGetTime)();
func_timeGetTime ptimeGetTime; 

Now, we should get the address of needed functions in run-time (using GetProcAddress API) and set them to the defined pointers:

C++
void SetFunctionAddresses()
{
	//Load bassmod.dll (included in package)
	HMODULE bassmod_module = LoadLibrary("bassmod.dll");
	
	//set bassmod.dll's function pointers in run-time
	pBASSMOD_Init = (func_BASSMOD_Init)GetProcAddress
				(bassmod_module, "BASSMOD_Init");
	pBASSMOD_MusicLoad = (func_BASSMOD_MusicLoad)GetProcAddress
				(bassmod_module, "BASSMOD_MusicLoad");
	pBASSMOD_MusicSetSync = (func_BASSMOD_MusicSetSync)GetProcAddress
				(bassmod_module, "BASSMOD_MusicSetSync");
	pBASSMOD_MusicPlay = (func_BASSMOD_MusicPlay)GetProcAddress
				(bassmod_module, "BASSMOD_MusicPlay");
	pBASSMOD_Free = (func_BASSMOD_Free)GetProcAddress
				(bassmod_module, "BASSMOD_Free");	
	
	//Load winmm.dll (in system directory)
	HMODULE winmm_module = LoadLibrary("winmm.dll");
	
	//set winmm.dll's function pointer (timeGetTime) in run-time
	ptimeGetTime = (func_timeGetTime)GetProcAddress(winmm_module, "timeGetTime");
} 

The only thing to do is initialize bassmod (BASSMOD_Init) and play the music.

Play from File

You can play xm file from file:

C++
//load music file
pBASSMOD_MusicLoad(FALSE, xmFileName, 0, 0,
   BASS_MUSIC_LOOP|BASS_MUSIC_RAMPS|BASS_MUSIC_SURROUND|BASS_MUSIC_CALCLEN);

Play from Memory

You can play xm file from memory. My example reads file, loads all of it in memory and then plays it from memory, but you can load in memory from your project's resource. You should load your xm file from resource and play it. Playing from memory is like this:

C++
//load the file to memory
HANDLE hfile = CreateFile(xmFileName, GENERIC_READ,0,0,
       OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
DWORD filesize = GetFileSize(hfile, 0);
BYTE *data = new BYTE[filesize];
DWORD read;
ReadFile(hfile, data, filesize, &read, NULL);
CloseHandle(hfile);

//load music file
pBASSMOD_MusicLoad(TRUE, data, 0, filesize,
   BASS_MUSIC_LOOP|BASS_MUSIC_RAMPS|BASS_MUSIC_SURROUND|BASS_MUSIC_CALCLEN);

I coded the project to replay the music but you can change BASSMOD_MusicSetSync's parameters to play once.

I defined two global variables in my project:

C++
char xmFileName[MAX_PATH]; 
bool playFromMemory; 

You can notice their use by their names. In my project's WinMain fucntion, you'll see these lines:

C++
//change this value to switch play-mode between memory and file
playFromMemory = true;

//set xm file to play
strcpy(xmFileName, "f:\\4EverBlue Morninsky.xm");

If you set playFromMemory to true, the application will play from memory and if you set it to false, the application will play it from file.

I used xmFileName directly, but you can use it as you want.

I included bassmod.h in the package that doesn't need indeed. I included it for special uses, because maybe someone wants to change function paramters, etc. There are a lot of value definitions in bassmod.h that you can use on your own (project doesn't need it).

I included a sample .xm file in the package: 4EverBlue Morninsky.xm.

You can play it using my project and players like KMplayer. It's cool.

I included bassmod.lib in the package too. It's unnecessary for my code, as you see in this picture:

no_additional_dependency.JPG

I included bassmod.lib, because I think maybe some people want to link bassmod.dll to their projects. I mention again that bassmod.lib is absolutely unnecessary.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)