200分求计算一首MIDI播放时间的例程。(200分)

  • 主题发起人 主题发起人 midiplayer
  • 开始时间 开始时间
M

midiplayer

Unregistered / Unconfirmed
GUEST, unregistred user!
求计算一首MIDI播放时间的例程。
 
不知这个行不行

来自:茶叶蛋 时间:99-4-18 14:54:44 ID:105723

Windows 3.X环境下定时器的使用
马兴录
一、问题的提出
在编制实时软件时,会遇到各种各样的定时要求,有的要求定时间
隔为几秒,有的要求几毫秒,甚至有要求以微秒为单位的。
作者在实际工作中,曾遇到这样的要求:同时使用多个定时器,有
的定时间隔为几百毫秒;而有的则要求几个毫秒;而且要求能通过I/O
板发出宽度仅为几十微秒的矩形波。
针对上述要求,作者使用Borland C++3.1在中文Windows 3.2下实
现了多种精度的定时器需要。

二、低精度定时器
Windows提供的定时器是建立在DOS的1CH中断基础上的。该中断
每秒钟发生18.2次,即时间间隔为54.945ms。如果定时间隔是该数的
整数倍时,使用这个定时器则是最简单的方法。
使用定时器的窗口可定义如下:
class WyWindows:public……
{
private:
virtual void TimerHandle ()=[WM-FIRST+WM-TIMER];
//响应定时消息WM-TIMER
};
在窗口的某个函数内启动定时器:
if (SetTimer(hWnd,1,110,NULL)==NULL)//时间间隔为//110ms,
定时器标识为1
{
错误处理;
}
定时器使用完后,应及时关闭:
KillTimer(1);//关闭1号定时器
如果定时间隔不是55ms的整数倍,则不能用上述方法实现。即使
使用SstTimer(..,..,1 00,NULL)来设置定时器也是不行的。实际使
用中会发现,这样作的定时间隔是110ms,而不是100ms.

三、高精度定时器
当定时间隔小于55ms,或者不是55ms的整数倍时,则必须另辟途径
。大家知道,虽然Wind ows是基于DOS的,但它对多媒体的支持却很优
秀。Windows下有一套多媒体编程接口,这套接口函数包含于mmsystem
.dll动态链接库中。Borland C++3.1提供了相应的头文件mmsystem.
h。在这个编程接口中,有一套定时器操作函数,可用来实现高精度的
定时器,其计时精度可达1ms。这套函数主要包括:
timeGetDevCaps()——获取定时器的一些参数;
timebegin
Period()——设置定时器的定时精度;
timeSetEvent ()——设置定时间隔并启动定时器;
timeKillEvent ()——关闭定时器;
timeEndPeriod ()——释放定时器。
根据面向对象的编程思想,对上述几个函数进行封装,实现了自定
义的MyTimer类。该类定义如下:
//----MyTimer.h
#define MY-TIMER(WM-USER+101)//定时器发给父窗口的消息ext
ern″C″
{
//定时器回调函数
void far PASCAL-export IntRout (WORD,WORD,DWORD,DWORD,DW
ORD);
}
-CLASSDEF(MyTimer)
typedef struct -df{
int Timer ID;//定时器标识
int MinRes;//最小计时精度
int DevCaps;//定时间隔
HWND hWnd;//拥有该定时器的窗口
long TCount;//总的计时时间
}MyTmID;
class -export Mytimer //MyTimer类定义
{
private:
MyTmID TData;
public:
MyTimer(HWND hw,WORD Gap);//参数为父窗口及定时间隔
-MyTimer();
BOOL Start();//定时器启动函数
void End();//关闭定时器
long GetTime();//获取定时时间
};
其主要函数实现如下:
//----MyTimer.cpp
#include
#include
#include "mxltimer.h"
PTModule MyTimerLib;
/*------定时器回调函数------*/
void far PASCAL-export IntTout (WORD,WORD,DWORD dwUser,D
WORD)
{My TmID *data;
data=(MyTmID *)dwUser;
if(data->TimeID)
{data->TCount+=data->DevCaps;//计时
if(data->hWnd!=NULL)
PostMessage(data->hWnd,MY-TIMER,0,01);
//向拥有该定时器//的窗口发送MY-TIMER消息
}
}
MyTimer::MyTimer(HWND hw,WORD Gap)
{
TIMECAPS Tcps;
//初始化定时器参数
if(timeGetDevCaps(&Tcps,sizeof(TIMECAPS))!=TIMERR-NOCAND
O)
{TData.MinRes=Tcps.wPeriodMin;
timebegin
Period(Tcps.wPeriodMin);
TData.TimerID=0;
TData.hwnd=hw;
TData.DevCaps=Gap;
TData.TCount=0;
}
}
MyTimer::-MyTimer 0//释放定时器
{
if (TData.Timer ID)
{timeKillEvent(TData.Timer ID);
timeEndPeriod(TData.MinRes);
TData.Timer ID=0;
}
}
BOOL MyTimer::Start()//启动定时器
{
TData.Tcount=0;
TData.TimerID=timeSetEvent(TData.DevCaps,TData.MinRes,(L
PTIMECALLBACK)Int
Ro
ut,(DWORD)&TData,TIME-PERIODIC);
if(!TData.TimerID) return 0;
return 1;
}
void MyTimer::End()//停止定时器
{
if(TData.TimerID)
{timeKillEvent(TData.TimerID);
TData.TimerID=0;
}
}
long MyTimer::GetTime()//获取计时时间
{
return TData.TCount;
}
MyTimer类应该用动态链接库来实现,即将上述程序单独编译为.D
LL文件,然后可以直接链接到自己的程序中去。该类的功能及使用方
法如下。
1.可以和任何一个窗口连接,定时向该窗口发送MY-TIMER消息。
使用方法和低精度定时器基本一致。
class MyWindow:public…
{private:
MyTimer *MTimerPtr;//定义一定时器指针
void TimerHandle()=[WM-FIRST+MY-TIMER];
//响应定时消息
.
.
};
在MyWindow的创建函数中建立定时器:
void MyWindow::SetupWindow()
{.
.
MTimerPtr=new MyTimer(hWnd,10);//定时间隔为10ms
}
在MyWindow的折构函数中释放定时器:
void MyWindow::-MyWindow()
{.
.
if(MTimerPtr)delete MTimerPtr;
}
可在任何合适的函数内启动或停止定时器:
启动定时器:if(MTimerPtr)MTimerPtr->start();
停止定时器:if(MTimerPtr)MTimerPtr->end();
在MyWindow的TimerHandle()函数中响应定时事件。
2.单纯用作计时器,如同一个跑表一样。这时定时器的拥有窗口
可设为NULL。其使用方法可见下面的程序示例。

四、矩形波的产生
如果要求产生微秒级的矩形波,则完全可以使用程序延时来实现
。在这段时间内完全占用CPU资源,因为这段时间毕竟是较短的。而如
果矩形波宽度在毫秒级以上,则可使用高精度定时器来实现。
要实现程序的准确延时,必须准确测定机器的运行速度。使用高
精度定时器可以准确测量机器速度。
void Test-Cpu-Speed()
{MyTimer*TmTemp;
TmTemp=new MyTimer(NULL,1);//定时精度1ms
if(TmTemp==NULL)return;
TmTemp->Start();//启动定时器
for (int i=0;i<20;i++)//延时
{
asm mov cx,0xffff;
tcpus:asm loop tcpus;
}
TmTemp->End();//关闭定时器
T50=(int)(65535L/(TmTemp->GetTime()*1000));
//延时50us的循环次数计算公式
}
发出50us宽度矩形波的程序如下:
outportb(..);
/*发出波形*/
asm mov cx,T50;//延时50us
13:asm loop 13;
outportb(..);//波形结束

五、结束语
一旦实现了高精度定时器,便可满足各种各样的定时要求。在使
用时应注意,当定时间隔很短时,应保证能及时响应定时消息,否则有
可能丢失定时消息,使定时不准。
(作者地址:青岛高校科技培训学院,266042)


 
wjiachun的方法是对的
 
什么啊,MIDI文件格式里应该有时间长度信息的
 
我的目的是读取MIDI文件中的数据从而计算出它的播放时间,MIDI文件中
好像没有时间长度信息。
 
MCI控制啦。
const char* AliasName="AviDev";
//打开文件
wsprintf(cmd,"open %s type sequencer alias %s ",LPCTSTR(FileName),AliasName);
mciSendString(cmd,NULL,0,NULL);
//设置时间格式
wsprintf(cmd,"set %s time format ms",AliasName);
mciSendString(cmd,NULL,0,NULL);
//得到播放时间,精确到毫秒
wsprintf(cmd,"status %s length",AliasName);
mciSendString(cmd,lpstrLength,len,NULL);
VC中的写法,Delphi中可能有些不同。
 
我这里有一个带源程序的控件,演示了MIDI的底层API的使用,
应该对你有所帮助,要的话就Mail to cemi-midi@163.net
 
接受答案了.
 
后退
顶部