首页
社区
课程
招聘
[原创]在VC中播放mid音乐的最简单方法
发表于: 2005-12-14 20:38 16054

[原创]在VC中播放mid音乐的最简单方法

2005-12-14 20:38
16054

前一段时间看到有人发布XM音乐的播放方法,主要用于在注册机加一个小巧的背景音乐.
但由于XM音乐比较少,比较小巧的就更少了,况且还依赖minifmod库.

所以考虑到以下因素,同样推荐在注册机加入MIDI音乐:
1.MIDI音乐文件使用更广泛,更容易获得,制作和编辑.
2.DirectMusic附带4MB音色库的Roland软波表,音质也不比XM差。
3.MIDI数据比XM数据更容易被压缩(MIDI文件压缩比在1:8左右).
4.不需要外部编程库,系统自带播放内核,添加的代码量极少.

这里给出一个最简单的MIDI音乐的播放方法,即使用DirectMusic高层库.
虽然利用MCI的高层也可以播放,但它似乎不支持内存载入,
而且无法避免与其他MIDI音乐的同时播放的冲突.
估计都有装了DirectX吧,播放的通用性应该没有问题.
但编译这个程序还需要装上DirectX SDK.


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 7
支持
分享
最新回复 (9)
雪    币: 298
活跃值: (445)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
2
好文章。。
2005-12-15 00:17
0
雪    币: 97697
活跃值: (200824)
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
3
2005-12-15 00:28
0
雪    币: 603
活跃值: (617)
能力值: ( LV12,RANK:660 )
在线值:
发帖
回帖
粉丝
4
恩,是个好的方法,我以前写的注册机是把MIDI数据写到磁盘上再播放,这个方法省了读写磁盘文件的步骤,方便了一些.但是手写那个MIDI的二进制数据也是个非常麻烦的事情.推荐流行时代Sen写的文章,将二进制数据写入资源,然后在内存中释放,这样就可以把手写MIDI数据的步骤也省略掉了,强烈推荐:

原文如下:

近来看到prince发贴甚多,想我自论坛创建来就没写什么东西,因为本人才疏学浅。今天突然感觉心中不快,写篇小儿文章让大家见笑。文中尚有很多愚钝之辞,还望各位兄弟指出。
很久以前love和小子就写了一个文件补丁工具,他们的是asm版本,我今天的是C的版本,如果没有兴趣,可以就此打住。

我们写程序的时候经常要生成或者是创建新的文件,这个是怎么做到的呢?老的CIH病毒是这么写的:
BYTE byExe[] = {
  0x4d, 0x87 ......
  ..... .....
}
这个如果要生成的文件很大的时候这个就会很难写,而且写出来的源文件会非常的庞大。这个时候,我们可以用载入资源的方式来解决。

用到的相关API:
FineResource:查找一个资源。我们是把相关要生成的文件载入,就是用这个函数来确定其资源的位置。
SizeofResource:获得资源的尺寸。
LoadResource:装载资源,装入到内存中。
LockResource:锁定资源,在内存中锁定。

好了,现在在VC的工程中载入这个文件吧。首先,我们把***.exe或者***.mid该成***.bin二进制文件,在资源文件上点击右键,选择Import(导入)。这里我们为自定义资源类型,即Custom Resource Type,Resource type为读者兴趣随便填写,这里用MyRes,资源名称用IDR_MyRes。

好了,现在就可以写一个函数进行文件的生成了:
BOOL Create()
{
    HRSRC hResInfo;
    HGLOBAL hResData;
    DWORD dwSize, dwWritten;
    HANDLE hFile;
    //开始所需的资源
    hResInfo = FineResource(NULL,MAKEINTRESOURCE(IDR_MyRes),"MyRes");
    if(hResInfo == NULL)
        return FALSE;
    //获得资源尺寸
    dwSize = SizeofResource(NULL,hResInfo);
    //装载
    hResData = LoadResource(NULL,hResInfo);
    if(hResData == NULL)
        return FALSE;
    //最重要的地方,写文件
    hFile = CreateFile("c:\\MyResG.exe",GENERIC_WRITE,0,NULL,CREATE_ALWAYS,0,NULL);
    if(hFile == NULL)
        return FALSE;
    WriteFile(hFile,(LPCVOID)LockResource(hResData),dwSize,&dwWritten,NULL);
    CloseHandle(hFile);
    return TRUE;
}
用这个函数就可以把资源文件的东西拖出来了,哈哈。完工
2005-12-15 13:04
0
雪    币: 217
活跃值: (99)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
5
最初由 prince 发布
恩,是个好的方法,我以前写的注册机是把MIDI数据写到磁盘上再播放,这个方法省了读写磁盘文件的步骤,方便了一些.但是手

写那个MIDI的二进制数据也是个非常麻烦的事情.推荐流行时代Sen写的文章,将二进制数据写入资源,然后在内存中释放,这样就可

以把手写MIDI数据的步骤也省略掉了,强烈推荐:
原文如下:
........

原来那些数据需要手写-_-!汗~~~
写个小程序来自动帮我们写吧!
[COLOR=blue]
#include<stdio.h>
void main()
{
    unsigned char c;
    unsigned int  n=0;
    FILE *fin =fopen("data.bin","rb");
    FILE *fout=fopen("data.h"  ,"wb");
    if(!fin||!fout) {printf("not found data.bin!\n");return;}
    fprintf(fout,"unsigned char *data[]={\r\n");
    while(1)
    {
        c=fgetc(fin);
        if(feof(fin)) break;
        fprintf(fout,"0x%02X,",c);
        if(++n%16==0) fprintf(fout,"\r\n");
    }
    fseek(fout,-1,SEEK_CUR);
    fprintf(fout,"\r\n};\r\n");
    fclose(fout);
    fclose(fin);
}

当然使用资源也是一个好办法,但比起直接使用数组缺点如下:
1.需要调用FineResource,SizeofResource,LoadResource,LockResource等函数,代码量多一些.
2.资源目录表和资源名称(如果使用字符串格式)需要一些额外的数据,且不能被加壳工具压缩.
3.使用资源就非常明显让别人轻易提取出该资源的数据.
4.便于某些无资源编译器或不方便编辑资源的编译器编译(如Dev C++).

还有另一个方法可以直接包含文件,而不是一堆十六进制数据.
但需要有nasm汇编器(把nasmw.exe放入VC编译程序目录中).
工程中添加文件mididata.asm,内容:
section .data
global _mididata
_mididata incbin "midi.mid"
;包含文件的文件名,与此文件同目录
设置mididata.asm的编译属性:
Custom Build/Commands: nasmw -f win32 -o $(OutDir)\$(InputName).obj $(InputPath)
Custom Build/Outputs:  $(OutDir)\$(InputName).obj
然后只需要在需要mididata的C++文件中加入下面一行即可:
extern "C" unsigned char mididata[12345]; //大小需要手动输入
哪个方法更方便自己决定吧......
2005-12-15 16:26
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
以上都不错,只是我不太懂,强烈支持
2005-12-15 16:57
0
雪    币: 603
活跃值: (617)
能力值: ( LV12,RANK:660 )
在线值:
发帖
回帖
粉丝
7
最初由 dwing 发布

当然使用资源也是一个好办法,但比起直接使用数组缺点如下:
1.需要调用FineResource,SizeofResource,LoadResource,LockResource等函数,代码量多一些.
2.资源目录表和资源名称(如果使用字符串格式)需要一些额外的数据,且不能被加壳工具压缩.
3.使用资源就非常明显让别人轻易提取出该资源的数据.
4.便于某些无资源编译器或不方便编辑资源的编译器编译(如Dev C++).

还有另一个方法可以直接包含文件,而不是一堆十六进制数据.
但需要有nasm汇编器(把nasmw.exe放入VC编译程序目录中).
工程中添加文件mididata.asm,内容:
section .data
global _mididata
_mididata incbin "midi.mid" ;包含文件的文件名,与此文件同目录
设置mididata.asm的编译属性:
Custom Build/Commands: nasmw -f win32 -o $(OutDir)\$(InputName).obj $(InputPath)
Custom Build/Outputs: $(OutDir)\$(InputName).obj
然后只需要在需要mididata的C++文件中加入下面一行即可:
extern "C" unsigned char mididata[12345]; //大小需要手动输入
哪个方法更方便自己决定吧......
........


呵呵,学习了!
2005-12-15 18:03
0
雪    币: 203
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
谁来转成asm的播放函数造福大家。
2005-12-15 19:14
0
雪    币: 217
活跃值: (99)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
9
最初由 hyzhang 发布
谁来转成asm的播放函数造福大家。


如果MASM32中包含COM库和DirectX库的话就可以转换.
2005-12-15 20:08
0
雪    币: 221
活跃值: (55)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
10
哦hoho,prince把老文都搬出来了
2005-12-24 00:34
0
游客
登录 | 注册 方可回帖
返回
//