标题：多媒体time函式
概述
处理多媒体计时器时，可以用毫秒指定两种不同的时间。第一个是延迟时间，第二个称为解析度。您可以认为解析度是容错误差。如果指定一个延迟100毫秒，而解析度是10毫秒，则计时器的实际延迟范围在90到110毫秒之间。
计时器的设备能力
使用计时器之前，应获得计时器的设备能力：
timeGetDevCaps (&timecaps, uSize) ;
第一个参数是TIMECAPS型态结构的指标，第二个参数是此结构的大小。TIMECAPS结构只有两个栏位，wPeriodMin和wPeriodMax。这是计时器装置驱动程式所支援的最小和最大的解析度值。如果呼叫timeGetDevCaps後再查看这些值，会发现wPeriodMin是1而wPeriodMax是65535，所以此函式并不是很重要。不过，得到这些解析度值并用于其他计时器函式呼叫是个好主意。
下一步呼叫
timeBeginPeriod (uResolution) ;
来指出程式所需要的计时器解析度的最低值。该值应在TIMECAPS结构所确定的范围之内。此呼叫允许为可能使用计时器的多个程式提供最好的计时器装置驱动程式。呼叫timeBeginPeriod及timeEndPeriod必须成对出现，我将在後面对timeEndPeriod作简短的描述。
现在可以真正设定一个计时器事件：
idTimer = timeSetEvent (        uDelay, uResolution, CallBackFunc, dwData, uFlag) ;
如果发生错误，从呼叫传回的idTimer将是0。在呼叫的下面，将从Windows里用uDelay毫秒来呼叫CallBackFunc函式，其中允许的误差由uResolution指定。uResolution值必须大于或等于传递给timeBeginPeriod的解析度。dwData是程式定义的资料，後来传递给CallBackFunc。最後一个参数可以是TIME_ONESHOT，也可以是TIME_PERIODIC。前者用于在uDelay毫秒数中获得一次CallBackFunc呼叫，而後者用于每个uDelay毫秒都获得一次CallBackFunc呼叫。
要在呼叫CallBackFunc之前终止只发生一次的计时器事件，或者暂停周期性的计时器事件，请呼叫
timeKillEvent (idTimer) ;
呼叫CallBackFunc後不必删除只发生一次的计时器事件。在程式中用完计时器以後，请呼叫
timeEndPeriod (wResolution) ;
其中的参数与传递给timeBeginPeriod的相同。
另两个函式的字首是time。函式
dwSysTime = timeGetTime () ;
传回从Windows第一次启动到现在的系统时间，单位是毫秒。函式
timeGetSystemTime (&mmtime, uSize) ;
MMTIME结构的指标
需要一个MMTIME结构的指标（与第一个参数一样），以及此结构的大小（与第二个参数一样）。虽然MMTIME结构可以在其他环境中用来得到非毫秒格式的系统时间，但此例中它都传回毫秒时间。所以timeGetSystemTime是多余的。
Callback函式只限于它所能做的Windows函式呼叫中。Callback函式可以呼叫PostMessage，PostMessage包含有四个计时器函式（timeSetEvent、timeKillEvent、timeGetTime和多余的timeGetSystemTime）、两个MIDI输出函式（midiOutShortMsg和midiOutLongMsg）以及调试函式OutputDebugStr。
很明显，设计多媒体计时器主要是用于MIDI序列而很少用于其他方面。当然，可以使用PostMessage来通知计时器事件的视窗讯息处理程式，而且视窗讯息处理程式可以做任何它想做的事，只是不能回应计时器callback自身的准确性。
Callback函式五个参数
Callback函式有五个参数，但只使用了其中两个参数：从timeSetEvent传回的计时器ID和最初作为参数传递给timeSetEvent的dwData值。
DRUM.C模组呼叫DRUMTIME.C中的DrumSetParams函式有很多次－建立DRUM视窗时、使用者在网格上单击或者移动卷动列时、从磁片上载入.DRM档案时以及清除网格时。DrumSetParams的唯一的参数是指向DRUM型态结构的指标，此结构型态在DRUMTIME.H定义。该结构以毫秒为单位储存拍子时间、速度（通常对应于音量）、序列中的拍数以及用于储存网格（为打击乐器和钢琴声设定）的两套47个32位元组的整数。这些32位元整数中的每一位元都对应序列的一拍。DRUM.C模组将在静态记忆体中维护一个DRUM型态的结构，并在呼叫DrumSetParams时向它传递一个指标。DrumSetParams只简单地复制此结构的内容。
启动序列
要启动序列，DRUM呼叫DRUMTIME中的DrumBeginSequence函式。唯一的参数就是视窗代号，其作用是通知。DrumBeginSequence打开MIDI Mapper输出设备，如果成功，则发送Program Change讯息来为MIDI通道0和9选择乐器声音（这些通道是基于0的，所以9实际指的是MIDI通道10，即打击乐器通道。另一个通道用于钢琴声）。DrumBeginSequence透过呼叫timeGetDevCaps和timeBeginPeriod来继续工作。在TIMER_RES定义的理想计时器解析度通常是5毫秒，但我定义了一个称作minmax的巨集来计算从timeGetDevCaps传回的限制范围以内的解析度。
下一个呼叫是timeSetEvent，用于确定拍子时间，计算解析度、callback函式DrumTimerFunc以及TIME_ONESHOT常数。DRUMTIME用的是只发生一次的计时器，而不是周期性计时器，所以速度可以随序列的执行而动态变化。timeSetEvent呼叫之後，计时器装置驱动程式将在延迟时间结束以後呼叫DrumTimerFunc。
DrumTimerFunccallback是DRUMTIME.C中的函式，在DRUMTIME.C中有许多重要的操作。变数iIndex储存序列中目前的拍子。Callback从为目前演奏的声音发送MIDI Note Off讯息开始。iIndex的初始值-1以防止第一次启动序列时发生这种情况。
接下来，iIndex递增并将其值连同使用者定义的一个WM_USER_NOTIFY讯息一起传递给DRUM中的视窗代号。wParam讯息参数设定为iIndex，以便在DRUM.C中，WndProc能够移动网格底部的「跳动的小球」。
DrumTimerFunc将下列事件作为结束：把Note On讯息发送给通道0和9的合成器上，并储存网格值以便下一次可以关闭声音，然後透过呼叫timeSetEvent来设定新的只发生一次的计时器事件。
停止序列
要停止序列，DRUM呼叫DrumEndSequence，其中唯一的参数可以设定为TRUE或FALSE。如果是TRUE，则DrumEndSequence按下面的程序立即结束序列：删除所有待决的计时器事件，呼叫timeEndPeriod，向两个MIDI通道发送「all notes off」讯息，然後关闭MIDI输出埠。当使用者决定终止程式时，DRUM用TRUE参数呼叫DrumEndSequence。
然而，当使用者在DRUM里的「Sequence」功能表中选择「Stop」时，程式将用FALSE作为参数呼叫DrumEndSequence。这就允许序列在结束之前完成目前的回圈。DrumEndSequence透过把bEndSequence整体变数设定为NULL来回应此呼叫。如果bEndSequence是TRUE，并且拍子的索引值设定为0，则DrumTimerFunc把使用者定义的WM_USER_FINISHED讯息发送给WndProc。WndProc必须通过用TRUE作为参数呼叫DrumEndSequence来回应该讯息，以便正确地结束计时器和MIDI埠的使用