使用 C++ 播放 XM - 从文件和内存






4.90/5 (10投票s)
使用未打包的 BASSMOD.dll 从文件和内存纯 C++ 播放 XM 音乐文件
引言
有些人喜欢在他们的应用程序中播放音乐。通常,可能是因为大小的原因,人们更喜欢 .xm 文件并播放它们。大多数情况是 MFC 和 Win32。un4seen.com 编写了 BASSMOD.dll,它可以播放它们。该项目使用此 DLL **而不链接到 bassmod.lib**。
背景
网上有一些代码示例可以做到这一点,但该项目有三个优点是其他项目所没有的
- 他们的代码使用 bassmod.lib 将应用程序链接到 bassmod.dll。因此,程序员无法从其资源中提取 bassmod.dll 并使用它。
- 他们的代码很混乱,人们无法轻松使用。
- bassmod.dll 使用 **PEtite 2.2** 打包。这可能会导致一些杀毒软件将其检测为病毒或可疑文件。或者用户可能会对此感到怀疑。我已经成功解除了 bassmod.dll 的打包,**您可以在您的项目中**使用解包后的 bassmod.dll。解包后的 bassmod.dll 包含在软件包中。
Using the Code
您只需要 bassmod.dll 就可以使用此代码(包含在软件包中)。为了方便起见,请将 bassmod.dll 复制到 Windows 目录。
当音乐播放到结尾时,它会重新播放。因此,音乐播放是一个永不返回的无限过程。为此,我创建了一个线程来播放音乐。
HANDLE hthread = CreateThread(NULL, NULL, MusicThread, NULL, NULL, NULL);
如果您的项目有一个窗口(MFC 或使用 CreateWindow),此代码将有效。但如果您的项目是 Win32,您应该为您的任务创建一个单独的线程并等待它。
WaitForSingleObject(hthread, INFINITE);
CloseHandle(hthread);
由于该项目不将 bassmod.dll 链接到 EXE,因此我们应该在运行时定义所需的函数指针。bassmod.dll 中需要的函数指针是
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;
winmm.dll 中需要的函数指针
typedef DWORD (__stdcall *func_timeGetTime)();
func_timeGetTime ptimeGetTime;
现在,我们应该在运行时获取所需函数的地址(使用 `GetProcAddress` API)并将其设置为已定义的指针。
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");
}
唯一需要做的就是初始化 bassmod (`BASSMOD_Init`) 并播放音乐。
从文件播放
您可以从文件播放 xm 文件
//load music file
pBASSMOD_MusicLoad(FALSE, xmFileName, 0, 0,
BASS_MUSIC_LOOP|BASS_MUSIC_RAMPS|BASS_MUSIC_SURROUND|BASS_MUSIC_CALCLEN);
从内存播放
您可以从内存播放 xm 文件。我的示例读取文件,将其全部加载到内存中,然后从内存播放,但您可以从项目的资源加载到内存中。您应该从资源加载您的 xm 文件并播放它。从内存播放如下所示:
//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);
我将项目编码为重复播放音乐,但您可以更改 `BASSMOD_MusicSetSync` 的参数以使其只播放一次。
我在我的项目中定义了两个全局变量
char xmFileName[MAX_PATH];
bool playFromMemory;
您可以通过它们的名字来理解它们的使用。在我的项目的 `WinMain` 函数中,您会看到这些行:
//change this value to switch play-mode between memory and file
playFromMemory = true;
//set xm file to play
strcpy(xmFileName, "f:\\4EverBlue Morninsky.xm");
如果将 `playFromMemory` 设置为 `true`,则应用程序将从内存播放;如果设置为 `false`,则应用程序将从文件播放。
我直接使用了 `xmFileName`,但您可以根据自己的需要使用它。
我在软件包中包含了 bassmod.h,但实际上并不需要。我将其包含是为了特殊用途,因为也许有人想更改函数参数等。bassmod.h 中有很多您可以自行使用的值定义(项目不需要它)。
我在软件包中包含了一个示例 .xm 文件:4EverBlue Morninsky.xm。
您可以使用我的项目和 KMplayer
等播放器播放它。这很酷。
我也在软件包中包含了 bassmod.lib。根据这张图片,我的代码是不需要它的:

我包含了 bassmod.lib,因为我认为也许有些人想将 bassmod.dll 链接到他们的项目中。我再次重申,**bassmod.lib 是绝对不必要的。**