怎样得到midi音频文件和wma音频文件的时间长度?

aqua_aqua 2002-12-14 06:58:22
我已经读出了midi音频文件的文件头,但是我不知道要怎么才能计算出midi音频文件的时间长度。请各位指点一下。谢谢。

还有,不知道wma的文件头的格式,不知道哪位兄弟知道的,麻烦告诉我一声。
...全文
369 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
fipl 2003-02-15
  • 打赏
  • 举报
回复
好厉害
westfly 2002-12-17
  • 打赏
  • 举报
回复
// 我以前做过的分析,你可以参考一下
4D 54 68 64 // MThd
00 00 00 06 // size, follow 6 bytes
----------------------------------------------------
00 00 // format
00 01 // track count
01 E0 // 480 ticks per quarter-note 那么每tick长为468750/480=976.5微秒=0.1毫秒
-----------------------------------------
----------------------------------------------------
00 // delta-time
FF // meta-event-flag
51 03 07 27 0E // track-tick size 四分音符长度=(07270E)=468,750微秒=0.5秒
----------------------------------------------------
...
-----------------------------

81 70 // delta-time = 0xF0 = 240, 转换为时值为240/480 = 1/2 拍子
47 // 按键号=4*16+7=71=第4音阶的B
00 // 力度=0
zhang865 2002-12-15
  • 打赏
  • 举报
回复
来学习,
AthlonxpX86 2002-12-15
  • 打赏
  • 举报
回复
midi分好几种格式,如GS,GM,XG....要得到统一的算法很难
AthlonxpX86 2002-12-15
  • 打赏
  • 举报
回复
参考资料:
"MIDI Systems and Control" Francis Rumsey 1990 Focal Press
"MIDI and Sound Book for the Atari ST" Bernd Enders and Wolfgang Klem 1989 M&T Publishing, Inc.
MIDI file specs and general MIDI specs were also obtained by sending e-mail to LISTSERV@AUVM.AMERICAN.EDU with the phrase GET MIDISPEC PACKAGE in the message.
------------------------------ DEC.CPP ------------------------------------

/* file dec.cpp

by Dustin Caldwell (dustin@gse.utah.edu)

*/


#include <dos.h>
#include <stdio.h>
#include <stdlib.h>

void helpdoc();

main()
{
FILE *fp;

unsigned char ch, c;

if((fp=fopen(_argv[1], "rb"))==NULL) /* open file to read */
{
printf("cannot open file %s\n",_argv[1]);
helpdoc();
exit(-1);
}

c=0;
ch=fgetc(fp);

while(!feof(fp)) /* loop for whole file */
{
printf("%u\t", ch); /* print every byte's decimal equiv. */
c++;
if(c>8) /* print 8 numbers to a line */
{
c=0;
printf("\n");
}

ch=fgetc(fp);
}

fclose(fp); /* close up */
}

void helpdoc() /* print help message */
{
printf("\n Binary File Decoder\n\n");

printf("\n Syntax: dec binary_file_name\n\n");

printf("by Dustin Caldwell (dustin@gse.utah.edu)\n\n");
printf("This is a filter program that reads a binary file\n");
printf("and prints the decimal equivalent of each byte\n");
printf("tab-separated. This is mostly useful when piped \n");
printf("into another file to be edited manually. eg:\n\n");
printf("c:\>dec sonata3.mid > son3.txt\n\n");
printf("This will create a file called son3.txt which can\n");
printf("be edited with any ascii editor. \n\n");
printf("(rec.exe may also be useful, as it reencodes the \n");
printf("ascii text file).\n\n");
printf("Have Fun!!\n");
}

---------------------------- REC.CPP ----------------------------------

/* File rec.cpp
by Dustin Caldwell (dustin@gse.utah.edu)
*/

#include <dos.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>

void helpdoc();

main()
{
FILE *rfp, *wfp;

unsigned char ch, c;
char s[20];

if((rfp=fopen(_argv[1], "r"))==NULL) /* open the read file */
{
printf("cannot open file %s \n",_argv[1]);
helpdoc();
exit(-1);
}

if((wfp=fopen(_argv[2], "wb"))==NULL) /* open the write file */
{
printf("cannot open file %s \n",_argv[1]);
helpdoc();
exit(-1);
}

c=0;

ch=fgetc(rfp);

while(!feof(rfp)) /* loop for whole file */
{

if(isalnum(ch)) /* only 'see' valid ascii chars */
{
c=0;
while(isdigit(ch)) /* only use decimal digits (0-9) */
{
s[c]=ch; /* build a string containing the number */
c++;
ch=fgetc(rfp);
}
s[c]=NULL; /* must have NULL terminator */

fputc(atoi(s), wfp);/* write the binary equivalent to file */

}

ch=fgetc(rfp); /* loop until next number starts */


}

fclose(rfp); /* close up */
fclose(wfp);
}


void helpdoc() /* print help message */
{
printf("\n Text File Encoder\n\n");

printf("\n Syntax: rec text_file_name binary_file_name\n\n");

printf("by Dustin Caldwell (dustin@gse.utah.edu)\n\n");
printf("This is a program that reads an ascii tab-\n");
printf("delimited file and builds a binary file where\n");
printf("each byte of the binary file is one of the decimal\n");
printf("digits in the text file.\n");
printf(" eg:\n\n");
printf("c:\>rec son3.txt son3.mid\n\n");
printf("(This will create a file called son3.mid which is\n");
printf("a valid binary file)\n\n");
printf("(dec.exe may also be useful, as it decodes binary files)\n\n");
printf("Have Fun!!\n");
}



 


AthlonxpX86 2002-12-15
  • 打赏
  • 举报
回复
标准MIDI文件格式



标准的MIDI文件格式就像奇异的兽。总体看来,它是那样的让你无法抗拒。当然,你怎样看它无关紧要,可是用足够多的描述符描述一段音乐并使它能够重现,可不是很少的工作就可以完成的。然而,它虽然复杂,但是真正理解之后,MIDI文件格式的结构还是很直观明了的。

在这里我必须放弃一些东西,因为毕竟我不是MIDI也不是MIDI文件专家!最近我为我的PC准备了一块Gravis 超音频音效卡,利用它听完几段MIDI文件(.mid)之后,想:“呵,我要是能够制作自己的MIDI(.mid)文件该多好啊!”嗯,经过烦人的几个小时之后,我发现,那些并不是没有价值的工作。但是,我是不会让一个冗长的文件格式就能够阻止的(此外,我告诉过我的妻子,计算机不是很难用的,而且我十分憎恨当一个伪君子)。那么,在这篇文章中如果发现什么错误,请让我知道,我会修改它的。同时,这份文档的范围并没有提供所有类型的MIDI命令和任何可能的文件配置!这篇基本指南将使读者能够(以中等的时间投资)制作出MIDI类型的文件。

1.概述:

一个MIDI文件基本上由两个部分组成,头块和轨道块。第二节讲述头块,第三节讲述轨道块。一个MIDI文件有一个头块用来描述文件的格式、许多的轨道块等内容。一个轨道可以想象为像一个大型多音轨录音机那样,你可以为某种声音、某种乐谱、某种乐器或者你需要的任何东西分配一个轨道。

2.头块:

头块出现在文件的开头,有三种方式来描述文件。头块看起来一直是这样的:
4D 54 68 64 00 00 00 06 ff ff nn nn dd dd

前4个字节等同于ASCII码MThd,接着MThd之后的4个字节是头的大小。它将一直是00 00 00 00 06,因为现行的头信息将一直是6字节。

ff ff是文件的格式,有3种格式:
0-单轨
1-多规,同步
2-多规,异步

单轨,很显然就只有一个轨道。同步多轨意味着所有轨道都是垂直同步的,或者其他的措辞为他们都在同一时间开始,并且可以表现一首歌的不同部分。异步多轨没有必要同时开始,而且可以完全的不同步。

nn nn 是MIDI文件中的轨道数。
dd dd 是每个4分音符delta-time节奏数(这之后将做详细介绍)。

3.轨道块:

头块之后剩下的文件部分是轨道块。每一个轨道包含一个头,并且可以包含你所希望的许多MIDI命令。轨道头与文件头及其相似:

4D 54 72 6B xx xx xx xx

与头一致,前4个字节是ASCII吗,这个是MTrk,紧跟MTrk的4个字节给出了以字节为单位的轨道的长度(不包括轨道头)。

在头之下是MIDI事件,这些事件同现行的可以被带有累加的MIDI合成器端口接受和发送的数据是相同的。一个MIDI 事件先于一个delta-time。一个delta-time是一个MIDI事件被执行后的节奏数,每个四分之一音符的节奏数先前已经定义在了文件的头块中。这个delta-time是一个可变长度的编码值。这种格式虽然混乱,可是允许根据需要利用多位表示较大的数值,这不会因为需求小的数值情况下以添零的方式浪费掉一些字节!数值被转换为7位的字节,并且除了最后一个字节以最高有效位是0外,各个字节最有意义的一位是1,。这就允许一个数值被一次一个字节地读取,你如果发现最高有效位是0,则这就是这个数值的最后一位(意义比较小)。依照MIDI说明,全部delta-time的长度最多超过4字节。

delta-time 之后就是MIDI事件,每个MIDI事件(除了正在运行的事件外)带有一个最高有效位总是1的命令字节(值将>128)。大部分命令的列表在附录A中。每个命令都有不同的参数和长度,但是接下来的数据将是最高有效位为零(值将<128)。这里有个例外就是meta-event,最高有效位可以是1。然而,meta-events需要一个长的参数以区分。

微小失误就可以导致混乱的是运行模式,这是现行MIDI命令所忽略的地方,并且最终发行的MIDI命令是假定的。这就意味这如果包含了命令,那么MIDI事件就是由delta-time与参数组成而转换的。

4.综述:

如果这份说明仅仅是使问题更加混乱,那么以下提供的例子可能有助于澄清问题!同时,两个公用程序和一个图解文件包含在这个文档里面:

DEC.EXE——这个公共程序是将二进制文件(比如.MID)转换成以十进制表示的对应每个字节的有标记界限的文本文件。

REC.EXE——这个公共程序是将有标记界限的十进制数文本文件对应的每一字节转换成二进制文件。

MIDINOTE.PS——这是一个对应键盘和五线谱的音符数字附录页。


附录A

1.MIDI事件命令

每个命令字节有两部分,左nybble(4位)包含现行的命令,右nybble包含将被执行的命令的通道号,这里有16各MIDI通道8个MIDI命令(命令nybble必须最高有效位是1的)。在下表中,X表示MIDI通道号。所有的音符即数据字节都<128(最高有效位是0)。

十六进制 二进制 数据 描述

8x 1000xxxx nn vv 音符关闭 (释放键盘)
nn=音符号
vv=速度

9x 1001xxxx nn vv 音符打开 (按下键盘)
nn=音符号
vv=速度

Ax 1010xxxx nn vv 触摸键盘以后
nn=音符号
vv=速度

Bx 1011xxxx cc vv 调换控制
cc=控制号
vv=新值

Cx 1100xxxx pp 改变程序(片断)
pp=新的程序号

Dx 1101xxxx cc 在通道后接触
cc=管道号

Ex 1110xxxx bb tt 改变互相咬和的齿轮 (2000H 表明缺省或没有改变)(什么意思搞不懂:)
bb=值的低7位(least sig)
tt=值的高7位 (most sig)

下表是没有通道的 meta-events列表 ,他们的格式是:

FF xx nn dd

所有的 meta-events 是以 FF 开头的命令 (xx),长度,或者含在数据的字节数(nn),现行的数据(dd)

十六进制 二进制 数据 描述
00 00000000 nn ssss 设定轨道的序号
nn=02 (两字节长度的序号)
ssss=序号

01 00000001 nn tt .. 你需要的所有文本事件
 nn=以字节为单位的文本长度
tt=文本字符

02 00000010 nn tt .. 同文本的事件, 但是用于版权信息
nn tt=同文本事件

03 00000011 nn tt .. 序列或者轨道名
nn tt=同文本事件

04 00000100 nn tt .. 轨道乐器名
nn tt=同文本事件

05 00000101 nn tt .. 歌词
nn tt=同文本事件

06 00000110 nn tt .. 标签
nn tt=同文本事件

07 00000111 nn tt .. 浮点音符
nn tt=同文本事件

2F 00101111 00 这个事件一定在每个轨道的结尾出现

51 01010001 03 tttttt 设定拍子
tttttt=微秒/四分音符

58 01011000 04 nn dd cc bb 拍子记号
nn=拍子记号分子
dd=拍子记号分母2=四分之一
3=8分拍, 等等.
cc=节拍器的节奏
bb=对四分之一音符标注的第32号数字

59 01011001 02 sf mi 音调符号
sf=升调/降调(-7=7 降调, 0=基准C调,7=7 升调)
mi=大调/小调(0=大调, 1=小调)

7F 01111111 xx dd .. 音序器的详细信息
xx=被发送的字节数
dd=数据

下表列出了控制整个系统的系统消息。这里没有MIDI通道数 (这些一般仅应用于MIDI键盘等.)

十六进制 二进制 数据 描述

F8 11111000 同步所必须的计时器
FA 11111010 开始当前的队列
FB 11111011 从停止的地方继续一个队列
FC 11111100 停止一个队列

下表列出的是与音符相对应的命令标记。
八度音阶¦¦ 音符号
# ¦¦
¦¦ C ¦ C# ¦ D ¦ D# ¦ E ¦ F ¦ F# ¦ G ¦ G# ¦ A ¦ A# ¦ B
-----------------------------------------------------------------------------
0 ¦¦ 0 ¦ 1 ¦ 2 ¦ 3 ¦ 4 ¦ 5 ¦ 6 ¦ 7 ¦ 8 ¦ 9 ¦ 10 ¦ 11
1 ¦¦ 12 ¦ 13 ¦ 14 ¦ 15 ¦ 16 ¦ 17 ¦ 18 ¦ 19 ¦ 20 ¦ 21 ¦ 22 ¦ 23
2 ¦¦ 24 ¦ 25 ¦ 26 ¦ 27 ¦ 28 ¦ 29 ¦ 30 ¦ 31 ¦ 32 ¦ 33 ¦ 34 ¦ 35
3 ¦¦ 36 ¦ 37 ¦ 38 ¦ 39 ¦ 40 ¦ 41 ¦
aqua_aqua 2002-12-15
  • 打赏
  • 举报
回复
westfly(西翔)
请问怎么得到通道标识,怎么知道一个磁道在哪个通道下呢?
westfly 2002-12-15
  • 打赏
  • 举报
回复
midi文件头不含播放总时间信息,
但可将同一channel下的各delta-time逐个相加得到。
wma的就不知道了。
AthlonxpX86 2002-12-15
  • 打赏
  • 举报
回复
http://www.nieni.org/bc4-6.htm
aqua_aqua 2002-12-15
  • 打赏
  • 举报
回复
: AthlonxpX86(一滴水)
这篇文章我已经看过了,英文原文我也看过了,但是对那个delta time 始终不知道怎么用?很苦恼呀。
crystal_heart 2002-12-14
  • 打赏
  • 举报
回复
up
aqua_aqua 2002-12-14
  • 打赏
  • 举报
回复
AthlonxpX86(一滴水) :
还在吗?谢谢你对我帮助。
不是我不用你说的方法,而是用MCI查询,要先打开设备,这个操作很费时。
而我现在用的是读文件头的方式,速度很快,只是比MediaPlay慢点。

哦,也许我没有说清楚我的意图,我是希望一个或多个曲目插入到表中,就能立刻显示出各曲目的时间长度。而用MCI查询就需要把每个曲目选入设备,然后查询,最后再关闭设备,下一个曲目又要这个过程,其中选入设备这个操作很费时。当我把5首曲目插入到表中的时候要等近半分钟才能看到各曲目的时间。
所以我用了读文件头的方式,现在已经能读出三种文件的时间长度了。接下来的MIDI文件头我也读出来了,但就是不会计算它的时间长度,不知道你能不能帮我。
另外,我在网上找了半天了,也没找到一篇关于wma文件格式的文章,郁闷!
AthlonxpX86 2002-12-14
  • 打赏
  • 举报
回复
midi的时间长度与文件大小无关,所以无法用V/t算,更高级的算法我也不清楚,我这里有N多个关于midi(英文,所以我没仔细研究过)的程序,要不要?
留下你的email,我发给你。
wma????不清楚,不过只要用MCI指令打开就可以用上述代码的到时间
AthlonxpX86 2002-12-14
  • 打赏
  • 举报
回复
不是给你说过了吗!
把midi文件用MCI指令打开后,得到设备id(m_wID),然后加入一下代码,就行了,(不要以为它知适合mp3)

MCI_STATUS_PARMS mciSP;

mciSP.dwItem=MCI_STATUS_LENGTH;
DWORD dwReturn=mciSendCommand(m_wID, MCI_STATUS, MCI_STATUS_ITEM,
(DWORD)(LPVOID)&mciSP);
if (dwReturn==0)
*dwLength=mciSP.dwReturn/1000;



aqua_aqua 2002-12-14
  • 打赏
  • 举报
回复
没人知道吗?
abrams 2002-12-14
  • 打赏
  • 举报
回复
关注
音频信息的获取与处理 一、知识点 1.声音的数字化表示。 (1).声音的三个要素:音调、音强和音色。 (2)音频文件的常用格式:WAV、MIDI、MP3、VOC、WMA、RM、CDA格式 2.音频信息的采集。 (1)在多媒体计算机中,声卡是获取音频信息的主要器件。 (2)声卡功能:采集来自话筒、收录机等音源的信号,并将其数字化形成数字音频;将数字音频还原为模拟音频信号,待放大后送到扬声器输出;对数字化音频进行编辑加工,以达到某一特殊效果。 以上功能均须通过声卡端口与相应的外部设备相连接起来才能实现。 线路输入(Linein):可与盒式录音机、唱机等相连进行录音。 线路输出(LineOut):可跳过音频卡的内置放大器,连接一个有源扬声器或外接放大器进行音频的输出。 话筒输入(MicIn):可与话筒相连,进行语音录人。 扬声器输出(SpeakerOut):从音频卡内置功率放大器连接扬声器进行输出。 游戏棒/MIDI接口(Joystick/MIDI):可将游戏棒或/MIDI设备连接到音频上。 3.数字音频的加工(CoolEditPro、Windows录音机)。 (1)裁剪声音:将声音中不需要的部分删除,保留需要的部分。 (2)连接声音:将两段声音首尾相接,或者将一段声音插人到另一段声音中间。、 (3)混合声音:将一段声音混合到另一段声音中,使两种声音能够同时听到。 (4)淡入/淡出:声音开始播放时音量由小逐渐变大称为淡人;播放结束时音量由大逐渐变小称为淡出。对声音做淡入/淡出处理,可以避免产生突然开始和突然停止的感觉。 4、数字音频常用的编码有:混合编码、参数编码、波形编码 5、声音的A/D A/D转换的一个关键步骤是声音的采样和量化 可用下面的公式估算声音数字化后每秒所需的存储量(假定不经压缩): 存储量(B)=(采样频率HZ×量化位数bit×声道数)/8 6、MIDI乐器数字接口 二、练习题 1、我们要将录音带上的模拟信号节目存入计算机,使用的设备是( )第四套9 A、显卡 B、声卡 C、网卡 D、光驱 2、采样与量化是数字音频系统中的两个最基本技术,以下正确的是( )第四套4 A、48KHZ是量化 B、16bit是量化 C、8bit比16bit质量高 D、16KHZ比48KHZ质量高 3、以下哪种不是音频文件( ) A RM B MIDI C WMA D SWF 4、以下哪种不是音频格式文件( ) A TGA B WMA C MP3 D WAV 5.关于MIDI音乐,说法不正确的是( ) A. MIDI是乐器数字化英文的缩写 B.MIDI记录的不是声波本身的数 C.MIDI音乐文件的容量比数字音乐文件的容量大 D.创作MIDI音乐,需要软件 6、Cool Edit Pro软件可以进行( ) A 、视频编辑  B、图像浏览 C、音频编辑 D、文字编辑 7、以下不是数字音频常用的编码是( ) A、混合编码 B、参数编码 C、波形编码 D、模拟编码 8、班级活动利用Windows系统提供的“录音机”录制学生朗诵的诗歌时,除了计算机外,至少还需( ) A、话筒  B、扫描仪  C、打印机  D、耳机(不含话筒) 9、利用MIDI设备输入的是一种(   ) A 、视频格式文件  B、压缩格式声音 C、模拟化声音 D、数字化声音 10、以下不是MIDI设备的是( ) A 、话筒  B、MIDI接口  C、合成器  D、音序器 11.Cool edit Pro软件可以编辑 ( ) A、音频和视频 B、音频 C、文字 D、图像 12、以下文件类型中,( )是音频格式。第一套14(综合分析题) (1).WAV (2).MP3 (3).BMP (4).JPG A、(1)和(2) B、(1)和(3) C、(2)和(4) D、(2)和(3) 13、以下( )是Windows的通用声音格式。第二套14(综合分析题) A、WAV B、MP3 C、BMP D、CAD 14、下列要素中( )不属于声音的三要素 第三套14(综合分析题) A、音调 B、音色 C、音律 D、音强 15、用Cool Edit Pro2.1软件编辑声音文件时,下列说法正确的是:( )多选 A、可以方便地对音频进行准确的剪切、粘贴处理,可以把后面的内容剪切后贴到前面,调整了原有的顺序,也称非线编 B、可以将不同的声音文件合成为一个,如将诗歌朗诵的声音文件与一剪梅音乐文件合并 C、不可以调整声音的高低 D、可以直接打开视频文件,对其中的声音进行编辑 16、如果CD音质的采样频率为44.1KHZ,量化位数为16bit,那么,一首4分钟的CD双声道立体声音乐的数据长度是多少?( ) A、40.4MB B、35MB C、39.7MB D、42MB 17、在数字音频信息获取与处理过程中,下列顺序正确的是( )。第一套13(综合分析题) A、A/D变换、采样、压缩、存储、解压缩、D/A变换 B、采样、压缩、A/D变换、存储、解压缩、D/A变换 C、采样、A/D变换、压缩、存储、解压缩、D/A变换 D、采样、D/A变换、压缩、存储、解压缩、A/D变换 18、下列采集的波形声音,( )的质量最好。第二套13(综合分析题) A、单声道、8位量化、22.05kHz采样频率 B、双声道、8位量化、44.1kHz采样频率 C、单声道、16位量化、22.05kHz采样频率 D、双声道、16位量化、44.1kHz采样频率 19、数字音频采样和量化过程所用的主要硬件是( )第五套4、第三套13(综合分析题) A、数字编码器 B、数字解码器 C、模拟到数字的转换器(a/d转换器) D、数字到模拟的转换器(d / a转换器) 20、录制声音的方法很多,.如用windows录音机录制声音,用录音笔录制或用软件录制等。一般情况下,一次性录制时,录制时间最短的是( ) . a) windows录音机录制 b) 录音笔录制 c) cooledit软件录制 d)磁带录音机录制 21、用cooledit pro2.1软件编辑声音文件时,若要删除某段内容时,在选好该部分后,不能使用下列哪些方法删除( ) a) 按delete键 b) 用退格键 c) 用快捷菜单中的cut命令 d) 用工具栏上的剪切按钮 22、下列方法中( )可以获得数字音频素材? (1)从CD-ROM音频库中获取MIDI音乐 (2)用Windows中的CD播放器录音 (3)用磁带录音机 (4)用MIDI作曲软件制作MIDI音乐 A、(1)(2)(4) B、(2)(4) C、(1)(3) D、全部

16,467

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧