精华内容
下载资源
问答
  • 音频技术与录音艺术译丛:MIDI手册(修订版) 平装 – 2013年5月1日 休伯 (David Miles Huber) (作者), 丁乔 (译者), 张磊 (译者), 周君 (译者) 《MIDI手册(修订版)》全面介绍了MIDI制作所涉及的各方面知识。内容涵盖...
  • 《现代音乐人编曲手册:传统管弦乐配器和MIDI音序制作必备指南》: 一本为录音棚乐队作曲和音译制作而作的实用指南 为现代录音棚乐队的音乐制作而进行传统乐队和MIDI乐队的配器法技巧的学习。 进行专业制作的完整创作...
  • #MIDI 蜂鸣器 MIDI beeper 是一个 Python 程序,它通过发出哔哔声来播放 MIDI 文件。... 你可以尝试编译这个修改过的 beep.c(记住chmod 4755 在手册页中提到)。 在撰写本文时,可以在以下位置找到该项目的原始代码:
  • MIDI 1.0(电子规范和协议) General MIDI 1(包括 GM 开发者指南) 标准 MIDI 文件 MIDI 显示控制 MIDI 机器控制 MIDI 时间码 在网站上还有所有自 1996 年以来增加的 MIDI 规范,并包括最近增加的针对 MIDI 数据...
  • 要知道哪些 MIDI 音符对应于控制器中的哪个按钮,请查看控制器手册或编译该程序,它会在屏幕上告诉您刚刚按下的音符。 这样您就可以编辑文件并使用所需的配置重新编译。 用法: sudo ./xwaxm2h “指向您的 MIDI ...
  • MIDI文件格式分析(补充和勘误)

    千次阅读 2018-04-12 15:40:10
    MIDI文件格式分析(补充和勘误) 本文是对《MIDI文件格式分析》博客链接的一点补充: 原文复制 vim编辑二进制文件的方法 文中制作的midi文件内容和改动 原文复制 MIDI文件属于二进制文件,这种文件一般都有...

    MIDI文件格式分析(补充和勘误)

    本文是对《MIDI文件格式分析》博客链接的一点补充:

    • 原文复制
    • vim编辑二进制文件的方法
    • 文中制作的midi文件内容和改动

    原文复制

    MIDI文件属于二进制文件,这种文件一般都有如下基本结构: 文件头+数据描述

    文件头一般包括文件的类型,因为Midi文件仅以.mid为扩展名的就有0类和1类两种,而大家熟悉的位图文件的格式就更多了,所以才会出现文件头这种东西。

    而数据描述部份是主体,我们现在来一起分析它的结构:

    在每个Midi文件的开头都有如下内容,它们的十六进制代码为:“4d 54 68 64 00 00 00 06 ff ff nn nn dd dd”。

    前四个是ASCII字符“MThd”是用来鉴别是否Midi文件,而随后的四个字节是指明文件头描述部分的字节数,它总是6,所以一定是“00 00 00 06”,以下是剩余部分的含义:
    这里写图片描述
    以上就是MIDI文件头了,后面的所有内容都是真正做事的,我们先来看看它的构成。

    MIDI的数据是由若干个格式相同的子数据构成的,这些子数据在多音轨的格式中记录了一个轨道的所有信息。多加一个音轨,就简单地把数据追加在前一音轨的后面就可以了,不过不要忘记更改文件头中的nn nn(轨道数)。

    先看全局音轨。全局音轨包括歌曲的附加信息(比如标题和版权)、歌曲速度和系统码(Sysx)等内容。

    不管是全局音轨还是含有音符的音轨,都以“4D 54 72 6B”开头,它其实是ASCII字符“MTrk”,其后跟着一个4个字节的整数,它标志了该轨道的字节数,这不包括前面的4个字节和本身的4个字节。这一点,我们可以在后面的例子中去理解。

    接着就是记录数据的地方了,每一个数据有着相同的结构:时间差+事件。

    所谓时间差,指的是前一个事件到该事件的时间数,它的单位是tick(MIDI的最小时间单位)。它的构成比较特殊,这里要用二进制来说明。

    一个字节有8位,如果仅使用7位,它可以表示0~127这128个数,而剩下的一位,则用来作为标志。如果要表示的数在以上范围,则这个标志为0,这时,一个7位的字节可以表示0~127tick。如果要表示的数超出了这个范围(比如240),则把标志设置成1,然后记录下高7位,剩下的留给下一个字节,在该例中240可以分解成128*1+112,这里的1就是第一个字节要记录的,加上标志位,应该为10000001,即十六进制的81;而112是下一个字节记录的,它的十六进制为70:所以要表示240这个时间,要写成81 70。同理,如果要表示65535tick,则可以先计算出65535=1282*3+1281*127+1280*127,然后得出结果:83 FF 7F。由此,我们反过来也可以知道如何确定时间差:只要标志位为0,则表示结束读取时间差。比如82 C0 03表示1282*2+1281*64+1280*3=40963,如果基本时间为120,则有341:043个四分音符。

    以这种方式记录整数的字节称为动态字节,它根据记录的整数改变自身的长度,这在后面还要用到,所以必须熟练计算。

    看完了这么麻烦的东西,我们再来看个更麻烦的东西:事件。在这些标准的解释后面,我们会通过一些例子来进一步掌握这些内容。

    事件大体上可以分为音符、控制器和系统信息这几个种类。对于这些事件,都有统一的表达结构:种类+参数。

    对于一个音符,由于它的有效范围是0~127,所以直接用00~7F作为“种类”,可以认为是个音符,比如3C表示中央C。而一个音符的最重要的参数是力度(也叫速度:velocity)。比如,3C 64 表示一个力度为十进制100的中央C音符。

    因为一个字节有8位,所以剩余的一位如果置1,再联合其他的7位,则可以表示各种信息。我们暂且无视一个音轨到底是全局的还是用于记录音符的。它们归根结底都是用来记录各种事件的,只不过有些应出现在全局音轨比较合乎逻辑而已。既然这样,我们就可以从下面的表来看事件:

    下表中,x表示音轨0~F,比如81表示松开第二轨的音符。
    这里写图片描述
    下表详细地列出了FF的详细情况,对于字节数由数据决定的情况,表中以“–”表示。
    这里写图片描述
    这些就是MIDI结构的全部内容,在下一讲,我们将通过一个实例来分析。

    要书写二进制(十六进制)文件,应该准备好一些工具,比如我自己用的是VC++,因为学习MIDI格式无非是想写它的软件,既然VC++可以编辑二进制文件,就将就着用吧。其次,应该找个可以编辑和播放MIDI文件的软件,比如Cakewalk,这样就可以开始了。

    首先书写文件头“4d 54 68 64 00 00 00 06”,我们直接写同步多音轨的格式,先写1个音轨,并以120为一个音符的基本时间。这样,随后的字节是:“00 01 00 01 00 78”。

    现在,如果用Cakewalk打开会失败,因为我们指定的音轨数为1,但是并没有书写任何音轨,如果改成“00 01 00 00 00 78”再打开,就不会出问题了。所以,今后如果更改了音轨数,千万不要忘记向“上头”汇报。

    把轨道数改回01,继续我们的实验。先写音轨的头信息:“4D 54 72 6B”(MTrk),因为我们还不能确定后面有多少字节,所以先把它假设成“00 00 00 00”,以后再回来改。

    我们先尝试设置歌曲的速度和节拍等基本信息。假设一个四分音符的时间是半秒,即0.5*106微秒。它的十六进制数是07A120,再看事件表,设置速度是51,但是在其前面必须是FF,然后它须要3个字节作为参数,因此字节数为03,参数为“07 A1 20”,也就是“FF 51 03 07 A1 20”。这是事件部分,不要忘记在其之前有个参数——时间差。这是一开始就应该设置的参数,因此时间差为00。所以,完整的事件应该是“00 FF 51 03 07 A1 20”,我们把这一段追加在Midi文件末尾。

    这时先不要急着用Cakewalk验证,因为我们还没有向“上级”报告,没错,把前面表示字节数的“00 00 00 00”改成“00 00 00 07”,如果用VC++作为二进制文件的编辑器,选择了事件后,可以在状态栏看到选择的字节长。保存后,再用Cakewalk打开,就可以看见速度是120。

    我们再来设置节拍和调号,因为一般用Cakewalk新建一个Midi会默认地设置成4/4,C大调,我们就改设成6/8,A大调。查阅事件表知道,58和59是分别用来设置节拍和调号的。虽然设置节拍的参数很多,但在现在的系统中,后两个参数是被忽略的,而且Cakewalk还会对其进行修正。因此,我们只要设置好实际有用的就可以了。分子是6,分母是8,所以第一个参数是06,第二个参数是03(23=8)。最后,补上前面的时间差和后面的两个被忽略的参数,它应该是“00 FF 58 04 06 03 00 00”;再看调号,A调有3个升号,因此可以这样的事件可以表示为“00 FF 59 02 03 00”。事实上,大小调是个被忽略的参数。我们统计一下至今为止事件的字节数,然后更改前面的参数,即把“00 00 00 07”改成“00 00 00 15”。保存后用Cakewalk打开,再进入五线谱窗口,就可以马上验证了。细心的你可能已经发现,进入五线谱窗口前和平常有些延迟,这是因为我们并没有设置好那些可以忽略的字节,而Cakewalk就是在对其进行重新验证,这一点,我们以后再讨论。

    用同样的方法,您可以很容易地设置歌曲的标题和版权,这作为一个练习,在这里就不多写了。我们现在学习写一个含有音符的轨道。首先您应该知道要做哪些事:1、写新音轨的信息头;2、向上级汇报多了一个音轨。接下来,我们开始写入一个简单的音符。

    假设向第一拍写一个中音A,这里可能要先说明一下,音符是从C0开始一起向上数的,数到中央C(C5)是十六进制的3C,则中音A应该为45,在附件中有详细的计算方法。我们知道在音乐中一个音符通常有三个属性:音高、力度和时值。可是我们在事件表中并没有看见有什么可以直接设置音符时值的标志。不错,事实上,音符的时值是由按下的时间和松开的时间决定的。我们假设要写入一个八分音符。它的Tick数是四分音符的一半,即60,十六进制表示成3C。我们先来看看与音符有关的标志。

    在事件表中,9x是用来打开一个音符,我们这里假设使用第7个通道(注意到MIDI有16个通道(Channel),而第10个被默认地用作打击乐,所以,我们在这个阶段(没有学习Sysx之前),先不要使用第10个通道),则9x中的x是6;再看它的参数,一个是音符,这里我们写入45,第二个是力度,我们用70,因为是一开始就触发的,所以前面的时间差还是00。这样我们就在第5个通道以力度112按下了一个中音A。对应的字节描述是“00 96 45 70”。它的时值不用想都知道一定是0,这取决于什么时候把它松开。

    特别地,如果一个音符的力度为0,则MIDI认为用户想松开这个键,因为9x已经打开了通道,所以我们直接写入一个带00力度的同一音符就可以决定这个音符的时值了。根据前面的分析,这个时间差应该是3C,所以我们在写入3C后写上音符45和它的力度00,即“3C 45 00”。统计好字节数并向这一轨的头信息中更新,然后保存到磁盘,用Cakewalk打开并进入事件列表窗口便可以验证了。

    在这个基础上,我们再尝试在A的后面增加一个四分音符中音#G。因为96已经打开了通道,我们没有必要每次都使用9x,只要输入事件信息即可。对于中音#G,它的十六进制是44,相对刚才输入00力度的A来说时间差为00,因此可以表示成“00 44 64”,这里我们已经假设力度为100;然后是松开它,因为是四分音符,所以时间差是78H,别忘记力度是00,它的字节应表示成“78 44 00”,做好后面的工作,然后验证看对不对。

    我们再做个稍微复杂一点的实验:在原来的基础上,在同一轨的第一拍加上一个附点四分中音D。这里就不能再使用追加的方法了,因为前面的事件已经过了3个八分音符的时间,无论再加上什么,都只会发生在后面,所以我们要在前面插入一些字节。

    9x已经打开了通道,我们直接在9x按下的音符后加上一个音符事件“00 3E 64”,这里的00显然是个时间差,3E是中音D,64是力度,也就是说,在按下中音A的同时按下了中音D。我们又按下一个键了,要在什么时候,在哪里松开才能保证输入的是个附点八分音符呢?首先,它的时值是3个八分音符,即180,这里还有一点要注意,180是个大于128的数,它的动态字节就应该表示成“81 34”,在哪里输入才好呢?如果你觉得在按下D后输入,或者在任何什么地方输入这个时间差,然后再写上“3E 00”可以表示松开的话就完全误解了时间差的概念。其实,我们只要简单地在松开#G的时候松开D就可以了,所以应该在末尾补上“00 3E 00”。统计好字节数后到Cakewalk中去验证验证吧。这里附有我们目前写下的Midi文件样本。

    到目前为此,我们应该可以输入任何形式的音符了,不过MIDI除了音符以外,还可以包括各种控制器和系统码,它们的地位不亚于音符,我们现在马上学习如何使用控制器。

    控制器比音符要简单多了,我们尝试在#G前加入相位控制(Pan),它的十进制代码是10,十六进制是0A,我们将参数设置成111,即十六进制的6F。首先查得控制器是Bx,这里的x和上面一样,也是6。接下来写入控制器号0A,然后是参数6F,别忘了前面的时间差是00。所以这段字节是“00 B6 0A 6F”,它应放在松开#G的事件之前,与按下#G同时。不过,一旦使用了非音符,而后面还有音符事件时,则必须重新通知打开音符,这说起来复杂,做起来还是比较容易的,我们只要稍微改写下一个音符事件即可:原本是“时间差+音符+力度”,我们加入一个打开音符的标志,成为“时间差+9x+音符+力度”即可。校验过头信息后,去Cakewalk中进行更进一步的检验便知它的可行。

    其实,时间差为00的控制事件如果出现的时间也是00,则在Cakewalk中会尽可能地把它们放在轨道信息中,而不在事件列表中重复。我们可以利用这一点给音轨设置初始乐器和音量,这就作为一个练习,在此就不再说明了。

    至于其他的诸如触后键等与控制器类似的格式在此就不多说了。在这里有必要提醒的是滑音。滑音的乐理范围是-8192~8191,但是在使用时参数是个正数,比如要设置成0,则应该是0-(-8192)=8192,它才是参数。8192的7位双字节表示成“8192 mod 128=00H;8192 div 128=40H”。如果时间差是00,则应表示成“00 E6 00 40”

    最后我们看看系统码。系统码的构成本来是“F0 厂家ID 设备号码 格式代码 传送命令 具体参数 F7”,而在文件中,则不以开头的“F0”为系统码,而字节数也仅记录剩余的系统码,比如XG的复位码是“F0 43 10 4C 00 00 7E 00 F7”,则在文件中应写成“00 F0 08 43 10 4C 00 00 7E 00 F7”,其中第一个00是时间差,F0是系统码标志,08是后面的字节数。有一点要注意的是,几个系统码不可以写在一起,比如“00 F0 0D 43 10 4C 00 00 7E 00 F7 F0 AA BB CC F7”或“00 F0 0C 43 10 4C 00 00 7E 00 F7 AA BB CC F7”都是不好的写法。如果存在以上系统码集,可以分成两个事件:“00 F0 08 43 10 4C 00 00 7E 00 F7 00 F0 04 AA BB CC F7”

    当然系统码可以写在任何音轨,不过一般我们会考虑把歌曲播放前发送的系统码写在全局音轨中,并把时间差设成00。

    作为一个参考,这里再附上一个MIDI样本。

    虽然我们只讨论了同步多音轨的格式,其实对于其他两种,比如较常见的单音轨格式,所有的事件只写在一个音轨中,即只要存在一个“MTrk”就足够了。而相对地,用于记录音轨数的两个字节也永远为“00 01”,连续事件如果出现的通道不同,也必须重新指定通道(8x~Ex)。在此不详细讨论了。

    音符十六进制的计算
    关于乐器选择
    RPN和NRPN
    

    在MIDI中,中央C是C5,最低音是C0,最高音是G5,要计算任何一个音符对应的十六进制,可以使用这个公式:

    假设音符是NO,表示第O八度的音名N,比如G2中,N为G,O为2,则它的十进制为O*12+N,N的值为了简便起见,用下表给出:

    这样G2的十进制值为2*12+7=31,十六进制为1F。

    若知道音符的十六进制,也可以很容易求出音符,比如64(16)=100(10),

    而100 div 12=8,100 mod 12=4,对应音符为E8。写成公式就是:

    N=B mod 12;O=B div 12;(设B为表示音符的字节的十进制数)

    乐器是MIDI中比较重要的因素,要选择所有的乐器不仅仅只是使用Cx号标志就能完成的,还必须结合BankSelect(乐队选择),而BankSelect其实是由0号控制器和32号控制器完成的,它们的十六进制代码分别是00和20.比如要选择出XG标准中的Slow Violin,它在第08H个乐队中的第28H号乐器中,所以它的完整代码应为“00 B0 00 00 00 20 08 00 C0 28”。我们来分析它的构成:这里我们假设时间差为00,所有信息都发给通道00,所以第一个00是时间差,B0是打开控制器的标志,并指定发送到通道00,接下来的00 00,是由控制器号00和控制器参数00构成的,它事实上是表示0号控制器的参数为0,即BankSelect-MSB的参数为0,然后是下一个事件,它是“00 20 08”,即时间差是00,使用20H号控制器,参数为08H,即BankSelect-LSB的参数是08H,这样就指定了Bank(乐队)。再下来就是“00 C0 28”,就是所谓的Patch Change事件了,它的时间差为00,参数是28H。这样就完成了标准的乐器选择。

    事实上,它是由三个事件共同完成的,如果某次选择乐器和上次的乐器有共同的参数,可以不必重复使用相关的操作。

    在本例中,您可能发现了一点,当连续使用同类操作时可以不必每次指定操作种类,比如这里的连续再次使用控制器,所以第二个控制器并没有使用B0作为标志,而是直接使用控制器号码和它的参数。这一点和音符是一样的。其实,如果连续使用Patch Change事件(我是说如果),则也可不必每次都写Cx,打开了一次就可以了;不过就Patch Change事件而言,连续地更换乐器的结果是仅最后一个有效而已。

    在前面的文档中并没有提及RPN和NRPN,其实它们是由四个连续的控制器来实现的。我们假设要使用RPN事件的Coarse Turning,它的参数假设是4096,则它的字节是“00 B0 65 00 00 64 02 00 06 20 00 26 00”,我们来分析这段字节:首先我们先看看RPN是由哪四个控制器组成的——首先设置RPN-MSB和RPN-LSB,分别对应的控制器是65H和64H,Coarse Turning的RPN码是2,所以MSB为0,LSB为2;然后是设置Data Entry MSB和Data Entry LSB,对应的控制器是06H和26H,而4096 div 128=32,4096 mod 128=0,对应的十六进制数分别是20H和00H。因此就构成了上面的字节。而NRPN和RPN原理是一样的,只不过不用RPN-MSB和RPN-LSB,而改用NRPN-MSB和NRPN-LSB而已,它们对应的十六进制数分别为63H和62H。

    原文
    MIDI文件属于二进制文件,这种文件一般都有如下基本结构: 文件头+数据描述

    文件头一般包括文件的类型,因为Midi文件仅以.mid为扩展名的就有0类和1类两种,而大家熟悉的位图文件的格式就更多了,所以才会出现文件头这种东西。

    而数据描述部份是主体,我们现在来一起分析它的结构:

    在每个Midi文件的开头都有如下内容,它们的十六进制代码为:“4d 54 68 64 00 00 00 06 ff ff nn nn dd dd”。

    前四个是ASCII字符“MThd”是用来鉴别是否Midi文件,而随后的四个字节是指明文件头描述部分的字节数,它总是6,所以一定是“00 00 00 06”,以下是剩余部分的含义:

    以上就是MIDI文件头了,后面的所有内容都是真正做事的,我们先来看看它的构成。

    MIDI的数据是由若干个格式相同的子数据构成的,这些子数据在多音轨的格式中记录了一个轨道的所有信息。多加一个音轨,就简单地把数据追加在前一音轨的后面就可以了,不过不要忘记更改文件头中的nn nn(轨道数)。

    先看全局音轨。全局音轨包括歌曲的附加信息(比如标题和版权)、歌曲速度和系统码(Sysx)等内容。

    不管是全局音轨还是含有音符的音轨,都以“4D 54 72 6B”开头,它其实是ASCII字符“MTrk”,其后跟着一个4个字节的整数,它标志了该轨道的字节数,这不包括前面的4个字节和本身的4个字节。这一点,我们可以在后面的例子中去理解。

    接着就是记录数据的地方了,每一个数据有着相同的结构:时间差+事件。

    所谓时间差,指的是前一个事件到该事件的时间数,它的单位是tick(MIDI的最小时间单位)。它的构成比较特殊,这里要用二进制来说明。

    一个字节有8位,如果仅使用7位,它可以表示0~127这128个数,而剩下的一位,则用来作为标志。如果要表示的数在以上范围,则这个标志为0,这时,一个7位的字节可以表示0~127tick。如果要表示的数超出了这个范围(比如240),则把标志设置成1,然后记录下高7位,剩下的留给下一个字节,在该例中240可以分解成128*1+112,这里的1就是第一个字节要记录的,加上标志位,应该为10000001,即十六进制的81;而112是下一个字节记录的,它的十六进制为70:所以要表示240这个时间,要写成81 70。同理,如果要表示65535tick,则可以先计算出65535=1282*3+1281*127+1280*127,然后得出结果:83 FF 7F。由此,我们反过来也可以知道如何确定时间差:只要标志位为0,则表示结束读取时间差。比如82 C0 03表示1282*2+1281*64+1280*3=40963,如果基本时间为120,则有341:043个四分音符。

    以这种方式记录整数的字节称为动态字节,它根据记录的整数改变自身的长度,这在后面还要用到,所以必须熟练计算。

    看完了这么麻烦的东西,我们再来看个更麻烦的东西:事件。在这些标准的解释后面,我们会通过一些例子来进一步掌握这些内容。

    事件大体上可以分为音符、控制器和系统信息这几个种类。对于这些事件,都有统一的表达结构:种类+参数。

    对于一个音符,由于它的有效范围是0~127,所以直接用00~7F作为“种类”,可以认为是个音符,比如3C表示中央C。而一个音符的最重要的参数是力度(也叫速度:velocity)。比如,3C 64 表示一个力度为十进制100的中央C音符。

    因为一个字节有8位,所以剩余的一位如果置1,再联合其他的7位,则可以表示各种信息。我们暂且无视一个音轨到底是全局的还是用于记录音符的。它们归根结底都是用来记录各种事件的,只不过有些应出现在全局音轨比较合乎逻辑而已。既然这样,我们就可以从下面的表来看事件:

    下表中,x表示音轨0~F,比如81表示松开第二轨的音符。

    下表详细地列出了FF的详细情况,对于字节数由数据决定的情况,表中以“–”表示。

    这些就是MIDI结构的全部内容,在下一讲,我们将通过一个实例来分析。

    要书写二进制(十六进制)文件,应该准备好一些工具,比如我自己用的是VC++,因为学习MIDI格式无非是想写它的软件,既然VC++可以编辑二进制文件,就将就着用吧。其次,应该找个可以编辑和播放MIDI文件的软件,比如Cakewalk,这样就可以开始了。

    首先书写文件头“4d 54 68 64 00 00 00 06”,我们直接写同步多音轨的格式,先写1个音轨,并以120为一个音符的基本时间。这样,随后的字节是:“00 01 00 01 00 78”。

    现在,如果用Cakewalk打开会失败,因为我们指定的音轨数为1,但是并没有书写任何音轨,如果改成“00 01 00 00 00 78”再打开,就不会出问题了。所以,今后如果更改了音轨数,千万不要忘记向“上头”汇报。

    把轨道数改回01,继续我们的实验。先写音轨的头信息:“4D 54 72 6B”(MTrk),因为我们还不能确定后面有多少字节,所以先把它假设成“00 00 00 00”,以后再回来改。

    我们先尝试设置歌曲的速度和节拍等基本信息。假设一个四分音符的时间是半秒,即0.5*106微秒。它的十六进制数是07A120,再看事件表,设置速度是51,但是在其前面必须是FF,然后它须要3个字节作为参数,因此字节数为03,参数为“07 A1 20”,也就是“FF 51 03 07 A1 20”。这是事件部分,不要忘记在其之前有个参数——时间差。这是一开始就应该设置的参数,因此时间差为00。所以,完整的事件应该是“00 FF 51 03 07 A1 20”,我们把这一段追加在Midi文件末尾。

    这时先不要急着用Cakewalk验证,因为我们还没有向“上级”报告,没错,把前面表示字节数的“00 00 00 00”改成“00 00 00 07”,如果用VC++作为二进制文件的编辑器,选择了事件后,可以在状态栏看到选择的字节长。保存后,再用Cakewalk打开,就可以看见速度是120。

    我们再来设置节拍和调号,因为一般用Cakewalk新建一个Midi会默认地设置成4/4,C大调,我们就改设成6/8,A大调。查阅事件表知道,58和59是分别用来设置节拍和调号的。虽然设置节拍的参数很多,但在现在的系统中,后两个参数是被忽略的,而且Cakewalk还会对其进行修正。因此,我们只要设置好实际有用的就可以了。分子是6,分母是8,所以第一个参数是06,第二个参数是03(23=8)。最后,补上前面的时间差和后面的两个被忽略的参数,它应该是“00 FF 58 04 06 03 00 00”;再看调号,A调有3个升号,因此可以这样的事件可以表示为“00 FF 59 02 03 00”。事实上,大小调是个被忽略的参数。我们统计一下至今为止事件的字节数,然后更改前面的参数,即把“00 00 00 07”改成“00 00 00 15”。保存后用Cakewalk打开,再进入五线谱窗口,就可以马上验证了。细心的你可能已经发现,进入五线谱窗口前和平常有些延迟,这是因为我们并没有设置好那些可以忽略的字节,而Cakewalk就是在对其进行重新验证,这一点,我们以后再讨论。

    用同样的方法,您可以很容易地设置歌曲的标题和版权,这作为一个练习,在这里就不多写了。我们现在学习写一个含有音符的轨道。首先您应该知道要做哪些事:1、写新音轨的信息头;2、向上级汇报多了一个音轨。接下来,我们开始写入一个简单的音符。

    假设向第一拍写一个中音A,这里可能要先说明一下,音符是从C0开始一起向上数的,数到中央C(C5)是十六进制的3C,则中音A应该为45,在附件中有详细的计算方法。我们知道在音乐中一个音符通常有三个属性:音高、力度和时值。可是我们在事件表中并没有看见有什么可以直接设置音符时值的标志。不错,事实上,音符的时值是由按下的时间和松开的时间决定的。我们假设要写入一个八分音符。它的Tick数是四分音符的一半,即60,十六进制表示成3C。我们先来看看与音符有关的标志。

    在事件表中,9x是用来打开一个音符,我们这里假设使用第7个通道(注意到MIDI有16个通道(Channel),而第10个被默认地用作打击乐,所以,我们在这个阶段(没有学习Sysx之前),先不要使用第10个通道),则9x中的x是6;再看它的参数,一个是音符,这里我们写入45,第二个是力度,我们用70,因为是一开始就触发的,所以前面的时间差还是00。这样我们就在第5个通道以力度112按下了一个中音A。对应的字节描述是“00 96 45 70”。它的时值不用想都知道一定是0,这取决于什么时候把它松开。

    特别地,如果一个音符的力度为0,则MIDI认为用户想松开这个键,因为9x已经打开了通道,所以我们直接写入一个带00力度的同一音符就可以决定这个音符的时值了。根据前面的分析,这个时间差应该是3C,所以我们在写入3C后写上音符45和它的力度00,即“3C 45 00”。统计好字节数并向这一轨的头信息中更新,然后保存到磁盘,用Cakewalk打开并进入事件列表窗口便可以验证了。

    在这个基础上,我们再尝试在A的后面增加一个四分音符中音#G。因为96已经打开了通道,我们没有必要每次都使用9x,只要输入事件信息即可。对于中音#G,它的十六进制是44,相对刚才输入00力度的A来说时间差为00,因此可以表示成“00 44 64”,这里我们已经假设力度为100;然后是松开它,因为是四分音符,所以时间差是78H,别忘记力度是00,它的字节应表示成“78 44 00”,做好后面的工作,然后验证看对不对。

    我们再做个稍微复杂一点的实验:在原来的基础上,在同一轨的第一拍加上一个附点四分中音D。这里就不能再使用追加的方法了,因为前面的事件已经过了3个八分音符的时间,无论再加上什么,都只会发生在后面,所以我们要在前面插入一些字节。

    9x已经打开了通道,我们直接在9x按下的音符后加上一个音符事件“00 3E 64”,这里的00显然是个时间差,3E是中音D,64是力度,也就是说,在按下中音A的同时按下了中音D。我们又按下一个键了,要在什么时候,在哪里松开才能保证输入的是个附点八分音符呢?首先,它的时值是3个八分音符,即180,这里还有一点要注意,180是个大于128的数,它的动态字节就应该表示成“81 34”,在哪里输入才好呢?如果你觉得在按下D后输入,或者在任何什么地方输入这个时间差,然后再写上“3E 00”可以表示松开的话就完全误解了时间差的概念。其实,我们只要简单地在松开#G的时候松开D就可以了,所以应该在末尾补上“00 3E 00”。统计好字节数后到Cakewalk中去验证验证吧。这里附有我们目前写下的Midi文件样本。

    到目前为此,我们应该可以输入任何形式的音符了,不过MIDI除了音符以外,还可以包括各种控制器和系统码,它们的地位不亚于音符,我们现在马上学习如何使用控制器。

    控制器比音符要简单多了,我们尝试在#G前加入相位控制(Pan),它的十进制代码是10,十六进制是0A,我们将参数设置成111,即十六进制的6F。首先查得控制器是Bx,这里的x和上面一样,也是6。接下来写入控制器号0A,然后是参数6F,别忘了前面的时间差是00。所以这段字节是“00 B6 0A 6F”,它应放在松开#G的事件之前,与按下#G同时。不过,一旦使用了非音符,而后面还有音符事件时,则必须重新通知打开音符,这说起来复杂,做起来还是比较容易的,我们只要稍微改写下一个音符事件即可:原本是“时间差+音符+力度”,我们加入一个打开音符的标志,成为“时间差+9x+音符+力度”即可。校验过头信息后,去Cakewalk中进行更进一步的检验便知它的可行。

    其实,时间差为00的控制事件如果出现的时间也是00,则在Cakewalk中会尽可能地把它们放在轨道信息中,而不在事件列表中重复。我们可以利用这一点给音轨设置初始乐器和音量,这就作为一个练习,在此就不再说明了。

    至于其他的诸如触后键等与控制器类似的格式在此就不多说了。在这里有必要提醒的是滑音。滑音的乐理范围是-8192~8191,但是在使用时参数是个正数,比如要设置成0,则应该是0-(-8192)=8192,它才是参数。8192的7位双字节表示成“8192 mod 128=00H;8192 div 128=40H”。如果时间差是00,则应表示成“00 E6 00 40”

    最后我们看看系统码。系统码的构成本来是“F0 厂家ID 设备号码 格式代码 传送命令 具体参数 F7”,而在文件中,则不以开头的“F0”为系统码,而字节数也仅记录剩余的系统码,比如XG的复位码是“F0 43 10 4C 00 00 7E 00 F7”,则在文件中应写成“00 F0 08 43 10 4C 00 00 7E 00 F7”,其中第一个00是时间差,F0是系统码标志,08是后面的字节数。有一点要注意的是,几个系统码不可以写在一起,比如“00 F0 0D 43 10 4C 00 00 7E 00 F7 F0 AA BB CC F7”或“00 F0 0C 43 10 4C 00 00 7E 00 F7 AA BB CC F7”都是不好的写法。如果存在以上系统码集,可以分成两个事件:“00 F0 08 43 10 4C 00 00 7E 00 F7 00 F0 04 AA BB CC F7”

    当然系统码可以写在任何音轨,不过一般我们会考虑把歌曲播放前发送的系统码写在全局音轨中,并把时间差设成00。

    作为一个参考,这里再附上一个MIDI样本。

    虽然我们只讨论了同步多音轨的格式,其实对于其他两种,比如较常见的单音轨格式,所有的事件只写在一个音轨中,即只要存在一个“MTrk”就足够了。而相对地,用于记录音轨数的两个字节也永远为“00 01”,连续事件如果出现的通道不同,也必须重新指定通道(8x~Ex)。在此不详细讨论了。

    音符十六进制的计算
    关于乐器选择
    RPN和NRPN
    

    在MIDI中,中央C是C5,最低音是C0,最高音是G5,要计算任何一个音符对应的十六进制,可以使用这个公式:

    假设音符是NO,表示第O八度的音名N,比如G2中,N为G,O为2,则它的十进制为O*12+N,N的值为了简便起见,用下表给出:
    这里写图片描述
    这样G2的十进制值为2*12+7=31,十六进制为1F。

    若知道音符的十六进制,也可以很容易求出音符,比如64(16)=100(10),

    而100 div 12=8,100 mod 12=4,对应音符为E8。写成公式就是:

    N=B mod 12;O=B div 12;(设B为表示音符的字节的十进制数)

    乐器是MIDI中比较重要的因素,要选择所有的乐器不仅仅只是使用Cx号标志就能完成的,还必须结合BankSelect(乐队选择),而BankSelect其实是由0号控制器和32号控制器完成的,它们的十六进制代码分别是00和20.比如要选择出XG标准中的Slow Violin,它在第08H个乐队中的第28H号乐器中,所以它的完整代码应为“00 B0 00 00 00 20 08 00 C0 28”。我们来分析它的构成:这里我们假设时间差为00,所有信息都发给通道00,所以第一个00是时间差,B0是打开控制器的标志,并指定发送到通道00,接下来的00 00,是由控制器号00和控制器参数00构成的,它事实上是表示0号控制器的参数为0,即BankSelect-MSB的参数为0,然后是下一个事件,它是“00 20 08”,即时间差是00,使用20H号控制器,参数为08H,即BankSelect-LSB的参数是08H,这样就指定了Bank(乐队)。再下来就是“00 C0 28”,就是所谓的Patch Change事件了,它的时间差为00,参数是28H。这样就完成了标准的乐器选择。

    事实上,它是由三个事件共同完成的,如果某次选择乐器和上次的乐器有共同的参数,可以不必重复使用相关的操作。

    在本例中,您可能发现了一点,当连续使用同类操作时可以不必每次指定操作种类,比如这里的连续再次使用控制器,所以第二个控制器并没有使用B0作为标志,而是直接使用控制器号码和它的参数。这一点和音符是一样的。其实,如果连续使用Patch Change事件(我是说如果),则也可不必每次都写Cx,打开了一次就可以了;不过就Patch Change事件而言,连续地更换乐器的结果是仅最后一个有效而已。

    在前面的文档中并没有提及RPN和NRPN,其实它们是由四个连续的控制器来实现的。我们假设要使用RPN事件的Coarse Turning,它的参数假设是4096,则它的字节是“00 B0 65 00 00 64 02 00 06 20 00 26 00”,我们来分析这段字节:首先我们先看看RPN是由哪四个控制器组成的——首先设置RPN-MSB和RPN-LSB,分别对应的控制器是65H和64H,Coarse Turning的RPN码是2,所以MSB为0,LSB为2;然后是设置Data Entry MSB和Data Entry LSB,对应的控制器是06H和26H,而4096 div 128=32,4096 mod 128=0,对应的十六进制数分别是20H和00H。因此就构成了上面的字节。而NRPN和RPN原理是一样的,只不过不用RPN-MSB和RPN-LSB,而改用NRPN-MSB和NRPN-LSB而已,它们对应的十六进制数分别为63H和62H。

    vim编辑二进制文件的方法

    参考链接

    打开
    vim -b x.mid
    设置16进制格式显示:
    :%!xxd
    只用编辑16进制部分的内容,修改其他部分的内容不会有其他影响期间不要保存改动
    最后保存前返回二进制形式:
    :%!xxd -r
    :wq

    文中制作的midi文件内容和改动

    原文描述中每个音轨结束后面没有加“00 ff 2f 00”, 同时在字节数中加上4,可以直接通过windows中的音乐播放器播放:

    00000000: 4d54 6864 0000 0006 0001 0002 0078 4d54 MThd………xMT
    00000010: 726b 0000 0019 00ff 5103 07a1 2000 ff58 rk……Q… ..X
    00000020: 0406 0300 0000 ff59 0203 0000 ff2f 004d …….Y…../.M
    00000030: 5472 6b00 0000 0b00 9645 703c 4500 00ff Trk……Ep

    展开全文
  • 用户手册 感谢您使用此程序。 简而言之,该程序将获取用户指定的文本文件,其中包含一系列音符的MIDI数字,然后转换信息并生成音符的音频文件。 本手册将引导您逐步使用该程序,解释所有功能并回答您可能遇到的任何...
  • 制作FL Studio MIDI脚本的综合指南(正在制作中)。 本指南不是Image-Line官方的替代,而是主要文档的补充指南,用于编译一些用于制作脚本的技巧和技术,以及针对可能不了解的初学者的更详细指南手册本身,因为...
  • 由于设备用完了,我们不再销售了,但是如果您想要一个,可以在这里找到所有原理图,手册,文档和代码来构建自己的设备。 将我们的设备连接到您的计算机,然后开始制作音乐! 完全无需任何额外软件即可即插即用,只...
  • html手册_HTML手册

    2020-08-13 00:00:07
    html手册Note: you can download a PDF / ePub / Mobi version of this book so you can read it offline. 注意:您可以下载本书的PDF / ePub / Mobi版本,以便离线阅读。 介绍 (Introduction) Welcome! I wrote ...

    html手册

    Note: you can download a PDF / ePub / Mobi version of this book so you can read it offline.

    注意:您可以下载本书的PDF / ePub / Mobi版本,以便离线阅读。

    介绍 (Introduction)

    Welcome! I wrote this book to help you quickly learn HTML and get familiar with the advanced HTML topics.

    欢迎! 我写这本书是为了帮助您快速学习HTML并熟悉高级HTML主题。

    HTML, a shorthand for Hyper Text Markup Language, is one of the most fundamental building blocks of the Web.

    HTML是超文本标记语言的缩写,是Web的最基本构建块之一。

    HTML was officially born in 1993 and since then it evolved into its current state, moving from simple text documents to powering rich Web Applications.

    HTML于1993年正式诞生,从那以后它演变成现在的状态,从简单的文本文档发展为强大的Web应用程序。

    This handbook is aimed at a vast audience.

    本手册面向广大读者。

    First, the beginner. I explain HTML from zero in a succinct but comprehensive way, so you can use this book to learn HTML from the basics.

    首先是初学者。 我以简洁而全面的方式从零开始解释HTML,因此您可以使用本书从基础上学习HTML。

    Then, the professional. HTML is often considered like a secondary thing to learn. It might be given for granted.

    然后,专业。 HTML通常被认为是次要的学习。 它可能是理所当然的。

    Yet lots of things are obscure to many people. Me included. I wrote this handbook to help my understanding of the topic, because when I need to explain something, I better make sure I first know the thing inside out.

    然而,许多事情对许多人来说还是晦涩难懂的。 我包括在内。 我写这本手册是为了帮助我理解该主题,因为当我需要解释某些内容时,最好确保我先从内而外地了解该内容。

    Even if you don't write HTML in your day to day work, knowing how HTML works can help save you some headaches when you need to understand it from time to time, for example while tweaking a web page.

    即使您在日常工作中不编写HTML,了解HTML的工作方式也可以帮助您在需要不时了解它(例如在调整网页时)时避免头痛。

    You can reach me on Twitter @flaviocopes.

    您可以通过Twitter @flaviocopes与联系

    My website is flaviocopes.com.

    我的网站是flaviocopes.com

    图书索引 (Book Index)

    前言 (PREFACE)

    HTML is the foundation of the marvel called the Web.

    HTML是称为Web的奇迹的基础。

    There is an incredible power underneath this rather simple and limited set of rules, which lets us -- developers, makers, designers, writers, and tinkerers -- craft documents, apps, and experiences for people all around the globe.

    在这套相当简单且有限的规则集之下,有着不可思议的力量,它使我们(开发人员,制作人员,设计师,作家和修补匠)能够为全球各地的人们制作文档,应用程序和体验。

    My first HTML book came out in 1997 and was called "HTML Unleashed". A big, lots-of-pages, long tome.

    我的第一本HTML书籍于1997年出版,被称为“ HTML Unleashed”。 一个很大的页面,很长。

    20+ years have passed, and HTML is still the foundation of the Web, with minimal changes from back then.

    20多年过去了,HTML仍然是Web的基础,从那时起变化很小。

    Sure, we got more semantic tags, presentational HTML is no longer a thing, and CSS has taken care of the design of things.

    当然,我们获得了更多的语义标签,表示性HTML不再是一回事,而CSS负责了事物的设计。

    HTML's success is based on one thing: simplicity.

    HTML的成功基于一件事: 简单性

    It resisted being hijacked into an XML dialect via XHTML, when eventually people realized that thing was way, way too complex.

    当最终人们意识到事情太复杂了,它拒绝通过XHTML被劫持为XML方言。

    It did so because of another feature it provides us: forgiveness. There are some rules, right, but after you learn those, you have a lot of freedom.

    之所以这样做,是因为它为我们提供了另一个功能: 宽恕 。 有一些规则,对,但是学习这些规则之后,您将拥有很多自由。

    Browsers learned to be resilient and to always try to do their best when parsing and presenting HTML to the users.

    浏览器学会了适应性强,并且在解析并向用户呈现HTML时总是尽力而为。

    And the whole Web platform did one thing right: it never broke backward compatibility. Pretty incredibly, we can go back to HTML documents written in 1991, and they look pretty much as they looked back then.

    整个Web平台做对了一件事情:它永远不会破坏向后兼容性。 令人难以置信的是,我们可以回溯到1991年编写HTML文档,它们看上去和那时一样。

    We even know what the first web page was. It's this: http://info.cern.ch/hypertext/WWW/TheProject.html

    我们甚至知道第一个网页是什么。 就是这样的: http : //info.cern.ch/hypertext/WWW/TheProject.html

    And you can see the source of the page, thanks to another big feature of the Web and HTML: we can inspect the HTML of any web page.

    由于Web和HTML的另一个重要功能,您可以看到页面的来源: 我们可以检查任何网页HTML

    Don't take this for granted. I don't know any other platform that gives us this ability.

    不要认为这是理所当然的。 我不知道有任何其他平台可以提供这种功能。

    The exceptional Developer Tools built into any browser let us inspect and take inspiration from HTML written by anyone in the world.

    内置在任何浏览器中的出色开发人员工具使我们能够检查世界上任何人编写HTML并从中汲取灵感。

    If you are new to HTML this book aims to help you get started. If you are a seasoned Web Developer this book will improve your knowledge.

    如果您不熟悉HTML,那么本书旨在帮助您入门。 如果您是一位经验丰富的Web开发人员,这本书将提高您的知识。

    I learned so much while writing it, even though I've been working with the Web for 20+ years, and I'm sure you'll find something new, too.

    即使我在Web上工作了20多年,我在编写它时也学到了很多东西,而且我相信您也会发现一些新东西。

    Or you'll re-learn something old you forgot.

    否则,您将重新学习忘记的旧知识。

    In any case, the goal of the book is to be useful to you, and I hope it succeeds.

    无论如何,这本书的目标是对您有用,我希望它能成功。

    HTML基础 (HTML BASICS)

    HTML is a standard defined by the WHATWG, an acronym for Web Hypertext Application Technology Working Group, an organization formed by people working on the most popular web browser. This means it's basically controlled by Google, Mozilla, Apple and Microsoft.

    HTML是WHATWG定义的标准, WHATWG是Web超文本应用程序技术工作组的缩写,该组织由使用最流行的Web浏览器的人们组成。 这意味着它基本上由Google,Mozilla,Apple和Microsoft控制。

    In the past the W3C (World Wide Web Consortium) was the organization in charge of creating the HTML standard.

    过去, W3C (万维网联盟)是负责创建HTML标准的组织。

    The control informally moved from W3C to WHATWG when it became clear that the W3C push towards XHTML was not a good idea.

    当很明显W3C向XHTML推进不是一个好主意时,该控件非正式地从W3C转移到WHATWG。

    If you've never heard of XHTML, here's a short story. In the early 2000s, we all believed the future of the Web was XML (seriously). So HTML moved from being an SGML-based authoring language to an XML markup language.

    如果您从未听说过XHTML,那么这里有个简短的故事。 在2000年代初期,我们都相信Web的未来(严重地是XML)。 因此,HTML已从基于SGML的创作语言转变为XML标记语言。

    It was a big change. We had to know, and respect, more rules. Stricter rules.

    这是一个很大的变化。 我们必须知道并尊重更多规则。 更严格的规则。

    Eventually browser vendors realized this was not the right path for the Web, and they pushed back, creating what is now known as HTML5.

    最终,浏览器供应商意识到这不是Web的正确路径,于是他们推迟了,创建了现在称为HTML5的东西。

    W3C did not really agree on giving up control of HTML, and for years we had 2 competing standards, each one aiming to be the official one. Eventually on 28 May 2019 it was made official by W3C that the "true" HTML version was the one published by WHATWG.

    W3C并未真正同意放弃对HTML的控制,多年来,我们有2个相互竞争的标准,每个标准都旨在成为正式标准。 最终,W3C于2019年5月28日正式宣布,“真正的” HTML版本是WHATWG发布的版本。

    I mentioned HTML5. Let me explain this little story. I know, it's kind of confusing up to now, as with many things in life when many actors are involved, yet it's also fascinating.

    我提到了HTML5。 让我解释一下这个小故事。 我知道,到目前为止,就像许多演员参与其中的生活中的许多事情一样,这令人感到困惑,但这也令人着迷。

    We had HTML version 1 in 1993. Here's the original RFC.

    我们在1993年拥有HTML版本1。 这是原始的RFC

    HTML 2 followed in 1995.

    HTML 2于1995年问世。

    We got HTML 3 in January 1997, and HTML 4 in December 1997.

    我们在1997年1月获得HTML 3,在1997年12月获得HTML 4

    Busy times!

    繁忙的时候!

    20+ years went by, we had this entire XHTML thing, and eventually we got to this HTML5 "thing", which is not really just HTML any more.

    20多年过去了,我们拥有了整个XHTML,最终我们有了这个HTML5“东西”,它不再仅仅是HTML

    HTML5 is a term that now defines a whole set of technologies, which includes HTML but adds a lot of APIs and standards like WebGL, SVG and more.

    HTML5是一个术语,现在定义了整套技术,其中包括HTML,但增加了许多API和标准,例如WebGL,SVG等。

    The key thing to understand here is this: there is no such thing (any more) as an HTML version now. It's a living standard. Like CSS, which is called "3", but in reality is a bunch of independent modules developed separately. Like JavaScript, where we have one new edition each year, but nowadays, the only thing that matters is which individual features are implemented by the engine.

    这里要了解的关键是:现在没有(像)HTML版本这样的东西。 这是生活水平。 类似于CSS,称为“ 3”,但实际上是一堆独立开发的独立模块。 与JavaScript一样,我们每年都有一个新版本,但是如今,唯一重要的是引擎实现了哪些单独的功能。

    Yes we call it HTML5, but HTML4 is from 1997. That's a long time for anything, let alone for the web.

    是的,我们称它为HTML5,但是HTML4是1997年发布的。对于任何事物来说,这都是很长的时间,更不用说对网络了。

    This is where the standard now "lives": https://html.spec.whatwg.org/multipage.

    这是标准现在“生效”的地方: https : //html.spec.whatwg.org/multipage

    HTML is the markup language we use to structure content that we consume on the Web.

    HTML是用于构造我们在Web上消费的内容的标记语言。

    HTML is served to the browser in different ways.

    HTML以不同的方式提供给浏览器。

    • It can be generated by a server-side application that builds it depending on the request or the session data, for example a Rails or Laravel or Django application.

      它可以由根据请求或会话数据构建它的服务器端应用程序生成,例如Rails或Laravel或Django应用程序。
    • It can be generated by a JavaScript client-side application that generates HTML on the fly.

      它可以由动态生成HTMLJavaScript客户端应用程序生成。
    • In the simplest case, it can be stored in a file and served to the browser by a Web server.

      在最简单的情况下,它可以存储在文件中,并由Web服务器提供给浏览器。

    Let's dive into this last case. Although in practice it's probably the least popular way to generate HTML, it's still essential to know the basic building blocks.

    让我们深入探讨最后一种情况。 尽管实际上,它可能是生成HTML的最不流行的方法,但是了解基本的构建基块仍然至关重要。

    By convention, an HTML file is saved with a .html or .htm extension.

    按照约定,HTML文件以.html.htm扩展名保存。

    Inside this file, we organize the content using tags.

    在此文件中,我们使用标签组织内容。

    Tags wrap the content, and each tag gives a special meaning to the text it wraps.

    标签包装内容,每个标签为其包装的文本赋予特殊含义。

    Let's make a few examples.

    让我们举几个例子。

    This HTML snippet creates a paragraph using the p tag:

    这个HTML片段使用p标签创建了一个段落:

    <p>A paragraph of text</p>

    This HTML snippet creates a list of items using the ul tag, which means unordered list, and the litags, which mean list item:

    该HTML代码段使用ul标签(表示无序列表 )和li标签(表示list item)创建项目列表

    <ul>
      <li>First item</li>
      <li>Second item</li>
      <li>Third item</li>
    </ul>

    When an HTML page is served by the browser, the tags are interpreted, and the browser renders the elements according to the rules that define their visual appearance.

    当浏览器为HTML页面提供服务时,将对标签进行解释,然后浏览器将根据定义其视觉外观的规则来渲染元素。

    Some of those rules are built-in, such as how a list renders or how a link is underlined in blue.

    其中一些规则是内置的,例如列表的呈现方式或链接的蓝色底线显示方式。

    Some other rules are set by you with CSS.

    其他一些规则由您使用CSS设置。

    HTML is not presentational. It's not concerned with how things look. Instead, it's concerned with what things mean.

    HTML不是演示性的。 它与事物的外观无关。 相反,它与事物的含义有关

    It's up to the browser to determine how things look, with the directives defined by who builds the page, with the CSS language.

    浏览器由CSS语言来决定外观,由谁来构建页面来定义指令。

    Now, those two examples I made are HTML snippets taken outside of a page context.

    现在,我做的两个例子是在页面上下文之外获取HTML代码段。

    HTML页面结构 (HTML page structure)

    Let's make an example of a proper HTML page.

    让我们举一个合适HTML页面的例子。

    Things start with the Document Type Declaration (aka doctype), a way to tell the browser this is an HTML page, and which version of HTML we are using.

    事情始于文档类型声明(又称doctype ),一种告诉浏览器这是HTML页面的方式,以及我们使用HTML版本。

    Modern HTML uses this doctype:

    现代HTML使用以下文档类型:

    <!DOCTYPE html>

    Then we have the html element, which has an opening and closing tag:

    然后,我们有了html元素,该元素具有一个开始和结束标记:

    <!DOCTYPE html>
    <html>
    ...
    </html>

    Most tags come in pairs with an opening tag and a closing tag. The closing tag is written the same as the opening tag, but with a /:

    大多数标签与开始标签和结束标签成对出现。 结束标记与开始标记的书写方式相同,但带有/

    <sometag>some content</sometag>

    There are a few self-closing tags, which means they don't need a separate closing tag as they don't contain anything in them.

    有一些自闭的标签,这意味着它们并不需要一个单独的结束标记,因为它们不包含其中的任何东西。

    The html starting tag is used at the beginning of the document, right after the document type declaration.

    html起始标记用于文档的开头,紧随文档类型声明之后。

    The html ending tag is the last thing present in an HTML document.

    html结束标记是HTML文档中的最后一件事。

    Inside the html element we have 2 elements: head and body:

    html元素内部,我们有2个元素: headbody

    <!DOCTYPE html>
    <html>
        <head>
        ...
        </head>
        <body>
        ...
        </body>
    </html>

    Inside head we will have tags that are essential to creating a web page, like the title, the metadata, and internal or external CSS and JavaScript. Mostly things that do not directly appear on the page, but only help the browser (or bots like the Google search bot) display it properly.

    head内部,我们将具有创建网页必不可少的标签,例如标题,元数据以及内部或外部CSS和JavaScript。 通常情况下,不会直接显示在页面上的东西只会帮助浏览器(或Google搜索机器人等机器人)正确显示它。

    Inside body we will have the content of the page. The visible stuff.

    body内部,我们将获得页面的内容。 可见的东西

    标签与元素 (Tags vs elements)

    I mentioned tags and elements. What's the difference?

    我提到了标签和元素。 有什么不同?

    Elements have a starting tag and a closing tag. In this example, we use the p starting and closing tags to create a p element:

    元素具有开始标签和结束标签。 在此示例中,我们使用p开始和结束标记创建一个p元素:

    <p>A paragraph of text</p>

    So, an element constitutes the whole package:

    因此,一个元素构成了整个

    • starting tag

      起始标签
    • text content (and possibly other elements)

      文字内容(可能还有其他元素)
    • closing tag

      结束标签

    If an element has doesn't have a closing tag, it is only written with the starting tag, and it cannot contain any text content.

    如果元素没有结束标记,则仅使用开始标记编写,并且不能包含任何文本内容。

    That said, I might use the tag or element term in the book meaning the same thing, except if I explicitly mention starting tag or ending tag.

    就是说,我可能会在书中使用标签或元素一词来表示相同的意思,除非我明确提到开始标签或结束标签。

    属性 (Attributes)

    The starting tag of an element can have special snippets of information we can attach, called attributes.

    元素的开始标记可以包含我们可以附加的特殊信息片段,称为属性

    Attributes have the key="value" syntax:

    属性具有key="value"语法:

    <p class="a-class">A paragraph of text</p>

    You can also use single quotes, but using double quotes in HTML is a nice convention.

    您也可以使用单引号,但是在HTML中使用双引号是一个很好的约定。

    We can have many of them:

    我们可以有很多:

    <p class="a-class" id="an-id">A paragraph of text</p>

    and some attributes are boolean, meaning you only need the key:

    并且一些属性是布尔值,这意味着您只需要键:

    <script defer src="file.js"></script>

    The class and id attributes are two of the most common you will find used.

    classid属性是您会发现最常用的两个属性。

    They have a special meaning, and they are useful both in CSS and JavaScript.

    它们具有特殊的含义,在CSS和JavaScript中都非常有用。

    The difference between the two is that an id is unique in the context of a web page; it cannot be duplicated.

    两者之间的区别在于, id在网页的上下文中是唯一的; 它不能重复。

    Classes, on the other hand, can appear multiple times on multiple elements.

    另一方面,类可以在多个元素上多次出现。

    Plus, an id is just one value. class can hold multiple values, separated by a space:

    另外, id只是一个值。 class可以包含多个值,以空格分隔:

    <p class="a-class another-class">A paragraph of text</p>

    It's common to use the dash - to separate words in a class value, but it's just a convention.

    通常使用破折号-将类值中的单词分开,但这只是一个约定。

    Those are just two of the possible attributes you can have. Some attributes are only used for one tag. They are highly specialized.

    这些只是您可能拥有的两个属性。 有些属性仅用于一个标签。 他们是高度专业化的。

    Other attributes can be used in a more general way. You just saw id and class, but we have other ones too, like style which can be used to insert inline CSS rules on an element.

    其他属性可以更一般的方式使用。 您刚刚看到了idclass ,但是我们还有其他一些,例如style ,可以用于在元素上插入内联CSS规则。

    不区分大小写 (Case insensitive)

    HTML is case insensitive. Tags can be written in all caps, or lowercase. In the early days, caps were the norm. Today lowercase is the norm. It is a convention.

    HTML不区分大小写。 标签可以全部大写,也可以小写。 在早期,上限是常态。 今天,小写字母已成为常态。 这是一个惯例。

    You usually write like this:

    您通常这样写:

    <p>A paragraph of text</p>

    not like this:

    不像这样:

    <P>A paragraph of text</P>

    空格 (White space)

    Pretty important. In HTML, even if you add multiple white spaces into a line, it's collapsed by the browser's CSS engine.

    相当重要 在HTML中,即使您在一行中添加了多个空格,浏览器CSS引擎也会将其折叠。

    For example the rendering of this paragraph:

    例如,本段的呈现:

    <p>A paragraph of text</p>

    is the same as this:

    与此相同:

    <p>        A paragraph of text</p>

    and the same as this:

    与此相同:

    <p>A paragraph
    
    of
               text          </p>

    > Using the white-space CSS property you can change how things behave. You can find more information on how CSS processes white space in the CSS Spec

    > 使用空白CSS属性,您可以更改行为方式。 您可以在CSS Spec中找到有关CSS如何处理空白的更多信息。

    I typically favor

    我通常喜欢

    <p>A paragraph of text</p>

    or

    要么

    <p>
        A paragraph of text
    </p>

    Nested tags should be indented with 2 or 4 characters, depending on your preference:

    嵌套标签应缩进2或4个字符,具体取决于您的偏好:

    <body>
        <p>
            A paragraph of text
        </p>
        <ul>
            <li>A list item</li>
        </ul>
    </body>

    Note: this "white space is not relevant" feature means that if you want to add additional space, it can make you pretty mad. I suggest you use CSS to make more space when needed.

    注意:此“空白不相关”功能意味着如果您要添加其他空间,可能会使您发疯。 我建议您在需要时使用CSS腾出更多空间。

    Note: in special cases, you can use the &nbsp; HTML entity (an acronym that means non-breaking space) - more on HTML entities later on. I think this should not be abused. CSS is always preferred to alter the visual presentation.

    注意:在特殊情况下,您可以使用&nbsp; HTML实体(缩写,表示不间断空格 )-有关HTML实体的更多信息。 我认为这不应被滥用。 始终首选使用CSS来更改视觉呈现。

    文件标题 (THE DOCUMENT HEADING)

    The head tag contains special tags that define the document properties.

    head标签包含定义文档属性的特殊标签。

    It's always written before the body tag, right after the opening html tag:

    它总是写在body标签之前,紧接在html标签之后:

    <!DOCTYPE html>
    <html>
        <head>
            ...
        </head>
        ...
    </html>

    We never use attributes on this tag. And we don't write content in it.

    我们永远不会在此标签上使用属性。 而且我们不会在其中编写内容。

    It's just a container for other tags. Inside it we can have a wide variety of tags, depending on what you need to do:

    它只是其他标签的容器。 在其中,根据您需要执行的操作,我们可以使用多种标签:

    • title

      title

    • script

      script

    • noscript

      noscript

    • link

      link

    • style

      style

    • base

      base

    • meta

      meta

    title标签 (The title tag)

    The title tag determines the page title. The title is displayed in the browser, and it's especially important as it's one of the key factors for Search Engine Optimization (SEO).

    title标签确定页面标题。 标题显示在浏览器中,它尤其重要,因为它是搜索引擎优化(SEO)的关键因素之一。

    script标签 (The script tag)

    This tag is used to add JavaScript into the page.

    此标记用于将JavaScript添加到页面中。

    You can include it inline, using an opening tag, the JavaScript code and then the closing tag:

    您可以使用开始标记,JavaScript代码和结束标记来内联包含它:

    <script>
    ..some JS
    </script>

    Or you can load an external JavaScript file by using the src attribute:

    或者,您可以使用src属性加载外部JavaScript文件:

    <script src="file.js"></script>

    The type attribute by default is set to text/javascript, so it's completely optional.

    默认情况下, type属性设置为text/javascript ,因此它是完全可选的。

    There is something pretty important to know about this tag.

    关于此标签,有一些非常重要的知识。

    Sometimes this tag is used at the bottom of the page, just before the closing </body> tag. Why? For performance reasons.

    有时,在页面底部</body>标记之前使用此标记。 为什么? 出于性能原因。

    Loading scripts by default blocks the rendering of the page until the script is parsed and loaded.

    默认情况下,加载脚本会阻止页面的呈现,直到脚本被解析并加载为止。

    By putting it at the bottom of the page, the script is loaded and executed after the whole page is already parsed and loaded, giving a better experience to the user over keeping it in the head tag.

    通过将其放在页面底部,可以在已经解析并加载整个页面之后加载并执行脚本,与保留在head标记中相比,可以为用户提供更好的体验。

    My opinion is that this is now bad practice. Let script live in the head tag.

    我的看法是,这现在是不好的做法。 让script保留在head标签中。

    In modern JavaScript we have an alternative this is more performant than keeping the script at the bottom of the page -- the defer attribute. This is an example that loads a file.js file, relative to the current URL:

    在现代JavaScript中,我们有一个替代方案,那就是比将脚本保留在页面底部( defer属性)更有效。 这是一个相对于当前URL加载file.js文件的示例:

    <script defer src="file.js"></script>

    This is the scenario that triggers the faster path to a fast-loading page, and fast-loading JavaScript.

    这是触发快速访问快速加载页面和JavaScript的场景。

    Note: the async attribute is similar, but in my opinion a worse option than defer. I describe why, in more detail, on page https://flaviocopes.com/javascript-async-defer/

    注意: async属性是相似的,但在我看来,比defer更糟糕的选择。 我会在https://flaviocopes.com/javascript-async-defer/上更详细地说明为什么

    noscript标签 (The noscript tag)

    This tag is used to detect when scripts are disabled in the browser.

    此标记用于检测何时在浏览器中禁用了脚本。

    Note: users can choose to disable JavaScript scripts in the browser settings. Or the browser might not support them by default.

    注意:用户可以选择在浏览器设置中禁用JavaScript脚本。 否则,浏览器可能默认不支持它们。

    It is used differently depending on whether it's put in the document head or in the document body.

    根据将其放置在文档头还是文档正文中,它的用法有所不同。

    We're talking about the document head now, so let's first introduce this usage.

    现在我们正在谈论文档头,因此让我们首先介绍这种用法。

    In this case, the noscript tag can only contain other tags:

    在这种情况下, noscript标签只能包含其他标签:

    • link tags

      link标签

    • style tags

      style标签

    • meta tags

      meta标记

    to alter the resources served by the page, or the meta information, if scripts are disabled.

    如果禁用了脚本,则更改页面提供的资源或meta信息。

    In this example I set an element with the no-script-alert class to display if scripts are disabled, as it was display: none by default:

    在此示例中,我使用no-script-alert类设置了一个元素,以显示是否禁用了脚本,因为它是display: none默认情况下, display: none

    <!DOCTYPE html>
    <html>
        <head>
            ...
            <noscript>
                <style>
                    .no-script-alert {
                        display: block;
                    }
                </style>
            </noscript>
    
            ...
        </head>
        ...
    </html>

    Let's solve the other case: if put in the body, it can contain content, like paragraphs and other tags, which are rendered in the UI.

    让我们解决另一种情况:如果放在正文中,它可以包含在UI中呈现的内容,例如段落和其他标签。

    The link tag is used to set relationships between a document and other resources.

    link标签用于设置文档和其他资源之间的关系。

    It's mainly used to link an external CSS file to be loaded.

    它主要用于链接要加载的外部CSS文件。

    This element has no closing tag.

    该元素没有结束标签。

    Usage:

    用法:

    <!DOCTYPE html>
    <html>
        <head>
            ...
            <link href="file.css" rel="stylesheet">
            ...
        </head>
        ...
    </html>

    The media attribute allows the loading of different stylesheets depending on the device capabilities:

    media属性允许根据设备功能加载不同的样式表:

    <link href="file.css" media="screen" rel="stylesheet">
    <link href="print.css" media="print" rel="stylesheet">

    We can also link to resources other than stylesheets.

    我们还可以链接到样式表以外的资源。

    For example we can associate an RSS feed using

    例如,我们可以使用

    <link rel="alternate" type="application/rss+xml" href="/index.xml">

    Or we can associate a favicon using:

    或者我们可以使用以下方式关联收藏夹图标:

    <link rel="apple-touch-icon" sizes="180x180" href="/assets/apple-touch-icon.png">
    
    <link rel="icon" type="image/png" sizes="32x32" href="/assets/favicon-32x32.png">
    
    <link rel="icon" type="image/png" sizes="16x16" href="/assets/favicon-16x16.png">

    This tag was also used for multi-page content, to indicate the previous and next page using rel="prev" and rel="next". Mostly for Google. As of 2019, Google announced it does not use this tag any more because it can find the correct page structure without it.

    这个标签用于多页内容,使用指示一个和下一个页面rel="prev"rel="next" 。 主要用于Google。 截至2019年, Google宣布不再使用此标签,因为没有它它可以找到正确的页面结构。

    style标签 (The style tag)

    This tag can be used to add styles into the document, rather than loading an external stylesheet.

    此标记可用于将样式添加到文档中,而不是加载外部样式表。

    Usage:

    用法:

    <style>
    .some-css {}
    </style>

    As with the link tag, you can use the media attribute to use that CSS only on the specified medium:

    link标签一样,您可以使用media属性仅在指定的介质上使用该CSS:

    <style media="print">
    .some-css {}
    </style>

    base标签 (The base tag)

    This tag is used to set a base URL for all relative URLs contained in the page.

    此标记用于为页面中包含的所有相对URL设置基本URL。

    <!DOCTYPE html>
    <html>
        <head>
            ...
            <base href="https://flaviocopes.com/">
            ...
        </head>
        ...
    </html>

    meta标记 (The meta tag)

    Meta tags perform a variety of tasks and they are very, very important.

    元标记执行各种任务,它们非常非常重要。

    Especially for SEO.

    特别是对于SEO。

    meta elements only have the starting tag.

    meta元素仅具有开始标记。

    The most basic one is the description meta tag:

    最基本的一个是description元标记:

    <meta name="description" content="A nice page">

    This might be used by Google to generate the page description in its result pages, if it finds it better describes the page than the on-page content (don't ask me how).

    可能是由谷歌被用来生成在结果页面的页面描述,如果找到更好的描述比对网页内容的页面(不要问我怎么样)。

    The charset meta tag is used to set the page character encoding. utf-8 in most cases:

    charset元标记用于设置页面字符编码。 utf-8在大多数情况下:

    <meta charset="utf-8">

    The robots meta tag instructs the Search Engine bots whether to index a page or not:

    robots元标记可指示搜索引擎robots是否对页面建立索引:

    <meta name="robots" content="noindex">

    Or if they should follow links or not:

    或者他们是否应该遵循链接:

    <meta name="robots" content="nofollow">

    You can set nofollow on individual links, too. This is how you can set nofollow globally.

    您也可以在单个链接上设置nofollow。 这样可以全局设置nofollow

    You can combine them:

    您可以将它们组合:

    <meta name="robots" content="noindex, nofollow">

    The default behavior is index, follow.

    默认行为是index, follow

    You can use other properties, including nosnippet, noarchive, noimageindex and more.

    您可以使用其他属性,包括nosnippetnoarchivenoimageindex等。

    You can also just tell Google instead of targeting all search engines:

    您也可以告诉Google而不是定位所有搜索引擎:

    <meta name="googlebot" content="noindex, nofollow">

    And other search engines might have their own meta tag, too.

    其他搜索引擎也可能具有自己的meta标签。

    Speaking of which, we can tell Google to disable some features. This prevents the translate functionality in the search engine results:

    说到这一点,我们可以告诉Google禁用某些功能。 这会阻止搜索引擎结果中的翻译功能:

    <meta name="google" content="notranslate">

    The viewport meta tag is used to tell the browser to set the page width based on the device width.

    viewport元标记用于告诉浏览器根据设备宽度设置页面宽度。

    <meta name="viewport" content="width=device-width, initial-scale=1">

    See more about this tag.

    查看有关此标签的更多信息

    Another rather popular meta tag is the http-equiv="refresh" one. This line tells the browser to wait 3 seconds, then redirect to that other page:

    另一个比较流行的meta标签是http-equiv="refresh"标签。 此行告诉浏览器等待3秒钟,然后重定向到该其他页面:

    <meta http-equiv="refresh" content="3;url=http://flaviocopes.com/another-page">

    Using 0 instead of 3 will redirect as soon as possible.

    使用0而不是3将尽快重定向。

    This is not a full reference; Other less-used meta tags exist.

    这不是完整的参考; 存在其他较少使用的元标记。

    After this document heading introduction, we can start diving into the document body.

    在介绍完本文档标题之后,我们可以开始深入研究文档正文。

    文件主体 (THE DOCUMENT BODY)

    After the closing head tag, we can only have one thing in an HTML document: the body element.

    在关闭head标签之后,我们在HTML文档中只能有一件东西: body元素。

    <!DOCTYPE html>
    <html>
        <head>
            ...
        </head>
        <body>
            ...
        </body>
    </html>

    Just like the head and html tags, we can only have one body tag in one page.

    就像headhtml标签一样,我们在一页中只能有一个body标签。

    Inside the body tag we have all the tags that define the content of the page.

    body标签内,我们具有定义页面内容的所有标签。

    Technically, the start and ending tags are optional. But I consider it a good practice to add them. Just for clarity.

    从技术上讲,开始和结束标记是可选的。 但是我认为添加它们是一个好习惯。 为了清楚起见。

    In the next chapters we'll define the variety of tags you can use inside the page body.

    在下一章中,我们将定义可在页面正文中使用的各种标签。

    But before, we must introduce a difference between block elements and inline elements.

    但是,在此之前,我们必须在块元素和内联元素之间引入区别。

    块元素与内联元素 (Block elements vs inline elements)

    Visual elements, the ones defined in the page body, can be generally classified in 2 categories:

    在页面正文中定义的视觉元素通常可以分为两类:

    • block elements (p, div, heading elements, lists and list items, ...)

      块元素( pdiv ,标题元素,列表和列表项,...)

    • inline elements (a, span, img, ...)

      内联元素( aspanimg ,...)

    What is the difference?

    有什么区别?

    Block elements, when positioned in the page, do not allow other elements next to them. To the left, or to the right.

    块元素位于页面中时,不允许其旁边有其他元素。 在左边或右边。

    Inline elements instead can sit next to other inline elements.

    相反,内联元素可以坐在其他内联元素旁边。

    The difference also lies in the visual properties we can edit using CSS. We can alter the width/height, margin, padding and border of block elements. We can't do that for inline elements.

    区别还在于我们可以使用CSS编辑的视觉属性。 我们可以更改块元素的宽度/高度,边距,填充和边框。 我们不能对内联元素执行此操作。

    Note that using CSS we can change the default for each element, setting a p tag to be inline, for example, or a span to be a block element.

    请注意,使用CSS我们可以更改每个元素的默认设置,例如将p标签设置为内联,或将span设置为block元素。

    Another difference is that inline elements can be contained in block elements. The reverse is not true.

    另一个区别是内联元素可以包含在块元素中。 反之则不成立。

    Some block elements can contain other block elements, but it depends. The p tag for example does not allow such option.

    某些块元素可以包含其他块元素,但这要视情况而定。 例如, p标签不允许这种选项。

    与文字互动的标签 (TAGS THAT INTERACT WITH TEXT)

    p标签 (The p tag)

    This tag defines a paragraph of text.

    该标签定义了一段文本。

    <p>Some text</p>

    It's a block element.

    这是一个块元素。

    Inside it, we can add any inline element we like, like span or a.

    在其中,我们可以添加任何喜欢的内联元素,例如spana

    We cannot add block elements.

    我们不能添加块元素。

    We cannot nest a p element into another one.

    我们不能将p元素嵌套到另一个元素中。

    By default browsers style a paragraph with a margin on top and at the bottom. 16px in Chrome, but the exact value might vary between browsers.

    默认情况下,浏览器为段落设置样式,在顶部和底部留有空白。 在Chrome中为16px ,但实际值可能因浏览器而异。

    This causes two consecutive paragraphs to be spaced, replicating what we think of a "paragraph" in printed text.

    这将导致两个连续的段落被隔开,从而复制了我们在打印文本中所认为的“段落”。

    span标签 (The span tag)

    This is an inline tag that can be used to create a section in a paragraph that can be targeted using CSS:

    这是一个内联标签,可用于在可使用CSS定位的段落中创建一个部分:

    <p>A part of the text <span>and here another part</span></p>

    br标签 (The br tag)

    This tag represents a line break. It's an inline element, and does not need a closing tag.

    此标记表示换行符。 这是一个内联元素,不需要结束标记。

    We use it to create a new line inside a p tag, without creating a new paragraph.

    我们使用它在p标记内创建新行,而无需创建新段落。

    And compared to creating a new paragraph, it does not add additional spacing.

    与创建新段落相比,它不会增加额外的间距。

    <p>Some text<br>A new line</p>

    标题标签 (The heading tags)

    HTML provides us 6 heading tags. From most important to least important, we have h1, h2, h3, h4, h5, h6.

    HTML为我们提供了6个标题标签。 从最重要到最不重要,我们有h1h2h3h4h5h6

    Typically a page will have one h1 element, which is the page title. Then you might have one or more h2 elements depending on the page content.

    通常,页面将具有一个h1元素,即页面标题。 然后,根据页面内容,您可能会有一个或多个h2元素。

    Headings, especially the heading organization, are also essential for SEO, and search engines use them in various ways.

    标题,尤其是标题组织,对于SEO也是必不可少的,搜索引擎以各种方式使用它们。

    The browser by default will render the h1 tag bigger, and will make the elements size smaller as the number near h increases:

    默认情况下,浏览器将使h1标签更大,并且随着h附近的数字增加,元素的大小将减小:

    All headings are block elements. They cannot contain other elements, just text.

    所有标题都是块元素。 它们不能包含其他元素,而只能是文本。

    strong标签 (The strong tag)

    This tag is used to mark the text inside it as strong. This is pretty important, it's not a visual hint, but a semantic hint. Depending on the medium used, its interpretation will vary.

    此标记用于将其中的文本标记为 。 这非常重要,它不是视觉提示,而是语义提示。 根据使用的介质,其解释会有所不同。

    Browsers by default make the text in this tag bold.

    默认情况下,浏览器使此标记中的文本变为粗体

    em标签 (The em tag)

    This tag is used to mark the text inside it as emphasized. Like with strong, it's not a visual hint but a semantic hint.

    此标记用于将其中的文本标记为强调 。 像strong一样,它不是视觉提示,而是语义提示。

    Browsers by default make the text in this italic.

    默认情况下,浏览器使用斜体显示文本。

    行情 (Quotes)

    The blockquote HTML tag is useful to insert citations in the text.

    blockquote HTML标记可用于在文本中插入引文。

    Browsers by default apply a margin to the blockquote element. Chrome applies a 40px left and right margin, and a 10px top and bottom margin.

    默认情况下,浏览器对blockquote元素应用边距。 Chrome会应用40px左右边距,以及10px上下边距。

    The q HTML tag is used for inline quotes.

    q HTML标记用于内联引号。

    水平线 (Horizontal line)

    Not really based on text, but the hr tag is often used inside a page. It means horizontal rule, and it adds a horizontal line in the page.

    并非完全基于文本,但是hr标签通常在页面内使用。 它表示horizontal rule ,并在页面中添加一条水平线。

    Useful to separate sections in the page.

    有助于分隔页面中的各个部分。

    代码块 (Code blocks)

    The code tag is especially useful to show code, because browsers give it a monospaced font.

    code标签对于显示代码特别有用,因为浏览器为它提供了等宽字体。

    That's typically the only thing that browsers do. This is the CSS applied by Chrome:

    这通常是浏览器唯一要做的。 这是Chrome应用CSS:

    code {
        font-family: monospace;
    }

    This tag is typically wrapped in a pre tag, because the code element ignores whitespace and line breaks. Like the p tag.

    此标记通常包装在pre标记中,因为code元素会忽略空格和换行符。 像p标签一样。

    Chrome gives pre this default styling:

    Chrome会pre此默认样式:

    pre {
        display: block;
        font-family: monospace;
        white-space: pre;
        margin: 1em 0px;
    }

    which prevents white space collapsing and makes it a block element.

    这样可以防止空格崩溃并使其成为块元素。

    清单 (Lists)

    We have 3 types of lists:

    我们有3种类型的列表:

    • unordered lists

      无序列表
    • ordered lists

      有序列表
    • definition lists

      定义清单

    Unordered lists are created using the ul tag. Each item in the list is created with the li tag:

    使用ul标签创建无序列表。 列表中的每个项目都是使用li标签创建的:

    <ul>
        <li>First</li>
        <li>Second</li>
    </ul>

    Ordered lists are similar, just made with the ol tag:

    有序列表是相似的,只是用ol标签制成:

    <ol>
        <li>First</li>
        <li>Second</li>
    </ol>

    The difference between the two is that ordered lists have a number before each item:

    两者之间的区别在于,有序列表在每个项目之前都有一个数字:

    Definition lists are a bit different. You have a term, and its definition:

    定义列表有些不同。 您有一个术语及其定义:

    <dl>
        <dt>Flavio</dt>
        <dd>The name</dd>
        <dt>Copes</dt>
        <dd>The surname</dd>
    </dl>

    This is how browsers typically render them:

    这是浏览器通常呈现它们的方式:

    I must say you rarely see them in the wild, for sure not much as ul and ol, but sometimes they might be useful.

    我必须说,您很少在野外看到它们,肯定不会像ulol那样多,但是有时它们可​​能有用。

    其他文字标签 (Other text tags)

    There is a number of tags with presentational purposes:

    有许多具有演示目的的标签:

    • the mark tag

      mark标签

    • the ins tag

      ins标签

    • the del tag

      del标签

    • the sup tag

      sup标签

    • the sub tag

      sub标签

    • the small tag

      small标签

    • the i tag

      i标签

    • the b tag

      b标签

    This is an example of the visual rendering of them which is applied by default by browsers:

    这是它们的视觉渲染的示例,默认情况下浏览器会应用它们:

    You might wonder, how is b different than strong? And how i is different than em?

    您可能想知道, bstrong什么不同? 怎么i比不同的em

    The difference lies in the semantic meaning. While b and i are a direct hint at the browser to make a piece of text bold or italic, strong and em give the text a special meaning, and it's up to the browser to give the styling. Which happens to be exactly the same as b and i, by default. Although you can change that using CSS.

    区别在于语义上。 bi是浏览器的直接提示,使一段文本变为粗体或斜体, strongem赋予该文本特殊的含义,这取决于浏览器的样式。 默认情况下,它恰好与bi完全相同。 尽管您可以使用CSS进行更改。

    There are a number of other, less used tags related to text. I just mentioned the ones that I see used the most.

    还有许多其他与文本相关的较少使用的标签。 我刚刚提到了使用最多的那些。

    链接 (LINKS)

    Links are defined using the a tag. The link destination is set via its href attribute.

    链接是使用a标签定义的。 链接目标是通过其href属性设置的。

    Example:

    例:

    <a href="https://flaviocopes.com">click here</a>

    Between the starting and closing tag we have the link text.

    在开始标记和结束标记之间,我们有链接文本。

    The above example is an absolute URL. Links also work with relative URLs:

    上面的示例是绝对URL。 链接也可以使用相对URL:

    <a href="/test">click here</a>

    In this case, when clicking the link the user is moved to the /test URL on the current origin.

    在这种情况下,单击链接时,用户将移动到当前来源的/test URL。

    Be careful with the / character. If omitted, instead of starting from the origin, the browser will just add the test string to the current URL.

    请注意/字符。 如果省略,则浏览器将代替将test字符串添加到当前URL,而不是从起点开始。

    Example, I'm on the page https://flaviocopes.com/axios/ and I have these links:

    例如,我在页面https://flaviocopes.com/axios/ ,我具有以下链接:

    • /test once clicked brings me to https://flaviocopes.com/test

      /test一次点击将我带到https://flaviocopes.com/test

    • test once clicked brings me to https://flaviocopes.com/axios/test

      单击一次test即可将我带到https://flaviocopes.com/axios/test

    Link tags can include other things inside them, not just text. For example, images:

    链接标签可以在其中包含其他内容,而不仅仅是文本。 例如,图像:

    <a href="https://flaviocopes.com">
        <img src="test.jpg">
    </a>

    or any other elements, except other <a> tags.

    或其他任何元素,但其他<a>标记除外。

    If you want to open the link in a new tab, you can use the target attribute:

    如果要在新选项卡中打开链接,则可以使用target属性:

    <a href="https://flaviocopes.com" target="_blank">open in new tab</a>

    容器标签和页面结构HTML (CONTAINER TAGS AND PAGE STRUCTURE HTML)

    容器标签 (Container tags)

    HTML provides a set of container tags. Those tags can contain an unspecified set of other tags.

    HTML提供了一组容器标记。 这些标签可以包含一组未指定的其他标签。

    We have:

    我们有:

    • article

      article

    • section

      section

    • div

      div

    and it can be confusing to understand the difference between them.

    理解它们之间的差异可能会造成混淆。

    Let's see when to use each one of them.

    让我们看看何时使用它们中的每一个。

    article (article)

    The article tag identifies a thing that can be independent from other things in a page.

    商品标签标识,可以是独立于页面其他东西事情

    For example a list of blog posts in the homepage.

    例如,主页中的博客文章列表。

    Or a list of links.

    或链接列表。

    <div>
        <article>
            <h2>A blog post</h2>
            <a ...>Read more</a>
        </article>
        <article>
            <h2>Another blog post</h2>
            <a ...>Read more</a>
        </article>
    </div>

    We're not limited to lists: an article can be the main element in a page.

    我们不仅限于列表:文章可以是页面中的主要元素。

    <article>
        <h2>A blog post</h2>
        <p>Here is the content...</p>
    </article>

    Inside an article tag we should have a title (h1-h6) and

    内部article标签,我们应该有一个标题( h1 - h6 )和

    section (section)

    Represents a section of a document. Each section has a heading tag (h1-h6), then the section body.

    代表文档的一部分。 每个节都有一个标题标签( h1 - h6 ),然后是节正文

    Example:

    例:

    <section>
        <h2>A section of the page</h2>
        <p>...</p>
        <img ...>
    </section>

    It's useful to break a long article into different sections.

    将较长的文章分成不同的部分很有用。

    Shouldn't be used as a generic container element. div is made for this.

    不应用作通用容器元素。 div是为此而设计的。

    div (div)

    div is the generic container element:

    div是通用容器元素:

    <div>
        ...
    </div>

    You often add a class or id attribute to this element, to allow it to be styled using CSS.

    您经常向该元素添加classid属性,以允许使用CSS设置其样式。

    We use div in any place where we need a container but the existing tags are not suited.

    我们在需要容器的任何地方使用div ,但现有标签不合适。

    This tag is used to create the markup that defines the page navigation. Into this we typically add an ulor ol list:

    此标记用于创建定义页面导航的标记。 通常,向其中添加一个ulol列表:

    <nav>
        <ol>
            <li><a href="/">Home</a></li>
            <li><a href="/blog">Blog</a></li>
        </ol>
    </nav>

    aside (aside)

    The aside tag is used to add a piece of content that is related to the main content.

    aside标签用于添加与主要内容相关的内容。

    A box where to add a quote, for example. Or a sidebar.

    例如,在其中添加引号的框。 或侧边栏。

    Example:

    例:

    <div>
      <p>some text..</p>
      <aside>
        <p>A quote..</p>
      </aside>
      <p>other text...</p>
    </div>

    Using aside is a signal that the things it contains are not part of the regular flow of the section it lives into.

    使用aside表示它包含的内容不是它所在的部分的常规流程的一部分。

    The header tag represents a part of the page that is the introduction. It can for example contain one or more heading tag (h1-h6), the tagline for the article, an image.

    header标记表示页面的一部分,即简介。 例如,它可以包含一个或多个标题标签( h1 - h6 ),商品的标语,图像。

    <article>
      <header>
          <h1>Article title</h1>
      </header>
      ...
    </div>

    main (main)

    The main tag represents the main part of a page:

    main标签代表页面的主要部分:

    <body>
      ....
      <main>
        <p>....</p>
      </main>
    </body>

    The footer tag is used to determine the footer of an article, or the footer of the page:

    footer标记用于确定文章的页脚或页面的页脚:

    <article>
     ....
      <footer>
        <p>Footer notes..</p>
      </footer>
    </div>

    形式 (FORMS)

    Forms are the way you can interact with a page, or an app, built with Web technologies.

    表单是您与使用Web技术构建的页面或应用程序进行交互的方式。

    You have a set of controls, and when you submit the form, either with a click to a "submit" button or programmatically, the browser will send the data to the server.

    您具有一组控件,并且在提交表单时(单击“提交”按钮或以编程方式单击),浏览器会将数据发送到服务器。

    By default this data sending causes the page to reload after the data is sent, but using JavaScript you can alter this behavior (not going to explain how in this book).

    默认情况下,此数据发送导致页面在发送数据后重新加载,但是使用JavaScript可以更改此行为(在本书中不做解释)。

    A form is created using the form tag:

    使用form标记创建一个form

    <form>
        ...
    </form>

    By default forms are submitted using the GET HTTP method. Which has its drawbacks, and usually you want to use POST.

    默认情况下,表单是使用GET HTTP方法提交的。 这有其缺点,通常您想使用POST。

    You can set the form to use POST when submitted by using the method attribute:

    您可以使用method属性将表单设置为在提交时使用POST:

    <form method="POST">
        ...
    </form>

    The form is submitted, either using GET or POST, to the same URL where it resides.

    使用GET或POST将表单提交到其驻留的相同URL。

    So if the form is in the https://flaviocopes.com/contacts page, pressing the "submit" button will make a request to that same URL.

    因此,如果表单位于https://flaviocopes.com/contacts页面中,则按“提交”按钮将向该URL发出请求。

    Which might result in nothing happening.

    可能什么也不会发生。

    You need something server-side to handle the request, and typically you "listen" for those form submit events on a dedicated URL.

    您需要服务器端来处理请求,通常您会“监听”专用URL上的那些表单提交事件。

    You can specify the URL via the action parameter:

    您可以通过action参数指定URL:

    <form action="/new-contact" method="POST">
        ...
    </form>

    This will cause the browser to submit the form data using POST to the /new-contact URL on the same origin.

    这将导致浏览器使用POST将表单数据提交到同一来源的/new-contact URL。

    If the origin (protocol + domain + port) is https://flaviocopes.com (port 80 is the default), this means the form data will be sent to https://flaviocopes.com/new-contact.

    如果来源(协议+域+端口)为https://flaviocopes.com (默认端口80),则意味着表单数据将发送到https://flaviocopes.com/new-contact

    I talked about data. Which data?

    我谈到了数据。 哪些数据?

    Data is provided by users via the set of controls that are available on the Web platform:

    用户通过Web平台上可用的一组控件提供数据:

    • input boxes (single line text)

      输入框(单行文本)
    • text areas (multiline text)

      文字区域(多行文字)
    • select boxes (choose one option from a drop-down menu)

      选择框(从下拉菜单中选择一个选项)
    • radio buttons (choose one option from a list always visible)

      单选按钮(从始终可见的列表中选择一个选项)
    • checkboxes (choose zero, one or more option)

      复选框(选择零,一个或多个选项)
    • file uploads

      文件上传
    • and more!

      和更多!

    Let's introduce each one of them in the following form fields overview.

    让我们在以下表单字段概述中介绍其中的每一个。

    input标签 (The input tag)

    The input field is one of the most widely used form elements. It's also a very versatile element, and it can completely change behavior based on the type attribute.

    input字段是使用最广泛的表单元素之一。 这也是一个非常通用的元素,它可以根据type属性完全更改行为。

    The default behavior is to be a single-line text input control:

    默认行为是单行文本输入控件:

    <input>

    Equivalent to using:

    等效于使用:

    <input type="text">

    As with all the other fields that follow, you need to give the field a name in order for its content to be sent to the server when the form is submitted:

    与后面的所有其他字段一样,您需要给该字段命名,以便在提交表单时将其内容发送到服务器:

    <input type="text" name="username">

    The placeholder attribute is used to have some text showing up, in light gray, when the field is empty. Useful to add a hint to the user for what to type in:

    当字段为空时, placeholder属性用于以浅灰色显示一些文本。 有助于向用户提示输入内容:

    <input type="text" name="username" placeholder="Your username">

    电子邮件 (Email)

    Using type="email" will validate client-side (in the browser) an email for correctness (semantic correctness, not ensuring the email address is existing) before submitting.

    使用type="email"将在提交之前验证客户端(在浏览器中)电子邮件的正确性(语义正确性,不能确保电子邮件地址存在)。

    <input type="email" name="email" placeholder="Your email">

    密码 (Password)

    Using type="password" will make every key entered appear as an asterisk (*) or dot, useful for fields that host a password.

    使用type="password"将使输入的每个键都显示为星号(*)或点,这对于承载密码的字段很有用。

    <input type="password" name="password" placeholder="Your password">

    号码 (Numbers)

    You can have an input element accept only numbers:

    您可以让输入元素仅接受数字:

    <input type="number" name="age" placeholder="Your age">

    You can specify a minimum and maximum value accepted:

    您可以指定可接受的最小值和最大值:

    <input type="number" name="age" placeholder="Your age" min="18" max="110">

    The step attribute helps identify the steps between different values. For example this accepts a value between 10 and 50, at steps of 5:

    step属性有助于识别不同值之间的步骤。 例如,以5的步长接受10到50之间的值:

    <input type="number" name="a-number"  min="10" max="50" step="5">

    隐藏的领域 (Hidden field)

    Fields can be hidden from the user. They will still be sent to the server upon the form submit:

    可以向用户隐藏字段。 提交表单后,它们仍将发送到服务器:

    <input type="hidden" name="some-hidden-field" value="some-value">

    This is commonly used to store values like a CSRF token, used for security and user identification, or even to detect robots sending spam, using special techniques.

    它通常用于存储诸如CSRF令牌之类的值,用于安全性和用户标识,甚至使用特殊技术来检测发送垃圾邮件的机器人。

    It can also just be used to identify a form and its action.

    它也可以仅用于识别表单及其动作。

    设定默认值 (Setting a default value)

    All those fields accept a predefined value. If the user does not change it, this will be the value sent to the server:

    所有这些字段均接受预定义的值。 如果用户不更改它,那么它将是发送到服务器的值:

    <input type="number" name="age" value="18">

    If you set a placeholder, that value will appear if the user clears the input field value:

    如果设置了占位符,则当用户清除输入字段值时,将显示该值:

    <input type="number" name="age" placeholder="Your age" value="18">

    表格提交 (Form submit)

    The type="submit" field is a button that, once pressed by the user, submits the form:

    type="submit"字段是一个按钮,一旦被用户按下,就会提交表单:

    <input type="submit">

    The value attribute sets the text on the button, which if missing shows the "Submit" text:

    value属性设置按钮上的文本,如果缺少该文本,则会显示“提交”文本:

    <input type="submit" value="Click me">

    表格验证 (Form validation)

    Browsers provide client-side validation functionality to forms.

    浏览器为表单提供客户端验证功能。

    You can set fields as required, ensuring they are filled, and enforce a specific format for the input of each field.

    您可以根据需要设置字段,以确保将其填充,并对每个字段的输入强制采用特定格式。

    Let's see both options.

    让我们看看两个选项。

    根据需要设置字段 (Set fields as required)

    The required attribute helps you with validation. If the field is not set, client-side validation fails and the browser does not submit the form:

    required属性可帮助您进行验证。 如果未设置该字段,则客户端验证将失败,并且浏览器不会提交表单:

    <input type="text" name="username" required>

    强制执行特定格式 (Enforce a specific format)

    I described the type="email" field above. It automatically validates the email address according to a format set in the specification.

    我在上面描述了type="email"字段。 它会根据规范中设置的格式自动验证电子邮件地址。

    In the type="number" field, I mentioned the min and max attribute to limit values entered to an interval.

    type="number"字段中,我提到了minmax属性以限制输入到间隔的值。

    You can do more.

    您可以做更多。

    You can enforce a specific format on any field.

    您可以在任何字段上强制使用特定格式。

    The pattern attribute gives you the ability to set a regular expression to validate the value against.

    pattern属性使您能够设置正则表达式来验证值。

    I recommend reading my Regular Expressions Guide at flaviocopes.com/javascript-regular-expressions/.

    我建议阅读flaviocopes.com/javascript-regular-expressions/上的《正则表达式指南》。

    pattern="https://.*"

    pattern =“ https://.*

    <input type="text" name="username" pattern="[a-zA-Z]{8}">

    其他领域 (Other fields)

    文件上传 (File uploads)

    You can load files from your local computer and send them to the server using a type="file" input element:

    您可以从本地计算机加载文件,然后使用type="file"输入元素将其发送到服务器:

    <input type="file" name="secret-documents">

    You can attach multiple files:

    您可以附加多个文件:

    <input type="file" name="secret-documents" multiple>

    You can specify one or more file types allowed using the accept attribute. This accepts images:

    您可以使用accept属性指定一种或多种允许的文件类型。 这接受图像:

    <input type="file" name="secret-documents" accept="image/*">

    You can use a specific MIME type, like application/json or set a file extension like .pdf. Or set multiple file extensions, like this:

    您可以使用特定的MIME类型(例如application/json或设置文件扩展名(例如.pdf 。 或设置多个文件扩展名,如下所示:

    <input type="file" name="secret-documents" accept=".jpg, .jpeg, .png">

    纽扣 (Buttons)

    The type="button" input fields can be used to add additional buttons to the form, that are not submit buttons:

    type="button"输入字段可用于向表单添加不是提交按钮的其他按钮:

    <input type="button" value="Click me">

    They are used to programmatically do something, using JavaScript.

    它们用于使用JavaScript以编程方式执行某些操作。

    There is a special field rendered as a button, whose special action is to clear the entire form and bring back the state of the fields to the initial one:

    有一个特殊的字段呈现为按钮,其特殊动作是清除整个表单并将字段的状态恢复为初始状态:

    <input type="reset">

    单选按钮 (Radio buttons)

    Radio buttons are used to create a set of choices, of which one is pressed and all the others are disabled.

    单选按钮用于创建一组选项,其中一个选项被按下,其他所有选项均被禁用。

    The name comes from old car radios that had this kind of interface.

    这个名字来自具有这种接口的老式汽车收音机。

    You define a set of type="radio" inputs, all with the same name attribute, and different valueattribute:

    您定义一组type="radio"输入,所有输入都具有相同的name属性和不同的value属性:

    <input type="radio" name="color" value="yellow">
    <input type="radio" name="color" value="red">
    <input type="radio" name="color" value="blue">

    Once the form is submitted, the color data property will have one single value.

    提交表单后, color数据属性将只有一个值。

    There's always one element checked. The first item is the one checked by default.

    总会检查一个元素。 第一项是默认情况下选中的项。

    You can set the value that's pre-selected using the checked attribute. You can use it only once per radio inputs group.

    您可以使用checked属性设置预先选择的值。 每个无线电输入组只能使用一次。

    选框 (Checkboxes)

    Similar to radio boxes, but they allow multiple values to be chosen, or none at all.

    与单选框相似,但是它们允许选择多个值,或者根本不选择。

    You define a set of type="checkbox" inputs, all with the same name attribute, and different valueattribute:

    您定义一组type="checkbox"输入,所有输入均具有相同的name属性和不同的value属性:

    <input type="checkbox" name="color" value="yellow">
    <input type="checkbox" name="color" value="red">
    <input type="checkbox" name="color" value="blue">

    All those checkboxes will be unchecked by default. Use the checked attribute to enable them on page load.

    All those checkboxes will be unchecked by default. Use the checked attribute to enable them on page load.

    Since this input field allows multiple values, upon form submit the value(s) will be sent to the server as an array.

    Since this input field allows multiple values, upon form submit the value(s) will be sent to the server as an array.

    Date and time (Date and time)

    We have a few input types to accept date values.

    We have a few input types to accept date values.

    The type="date" input field allows the user to enter a date, and shows a date picker if needed:

    The type="date" input field allows the user to enter a date, and shows a date picker if needed:

    <input type="date" name="birthday">

    The type="time" input field allows the user to enter a time, and shows a time picker if needed:

    The type="time" input field allows the user to enter a time, and shows a time picker if needed:

    <input type="time" name="time-to-pickup">

    The type="month" input field allows the user to enter a month and a year:

    The type="month" input field allows the user to enter a month and a year:

    <input type="month" name="choose-release-month">

    The type="week" input field allows the user to enter a week and a year:

    The type="week" input field allows the user to enter a week and a year:

    <input type="week" name="choose-week">

    All those fields allow to limit the range and the step between each value. I recommend checking MDN for the little details on their usage.

    All those fields allow to limit the range and the step between each value. I recommend checking MDN for the little details on their usage.

    The type="datetime-local" field lets you choose a date and a time.

    The type="datetime-local" field lets you choose a date and a time.

    <input type="datetime-local" name="date-and-time">

    Here is a page to test them all: https://codepen.io/flaviocopes/pen/ZdWQPm

    Here is a page to test them all: https://codepen.io/flaviocopes/pen/ZdWQPm

    Color picker (Color picker)

    You can let users pick a color using the type="color" element:

    You can let users pick a color using the type="color" element:

    <input type="color" name="car-color">

    You set a default value using the value attribute:

    You set a default value using the value attribute:

    <input type="color" name="car-color" value="#000000">

    The browser will take care of showing a color picker to the user.

    The browser will take care of showing a color picker to the user.

    Range (Range)

    This input element shows a slider element. People can use it to move from a starting value to an ending value:

    This input element shows a slider element. People can use it to move from a starting value to an ending value:

    <input type="range" name="age" min="0" max="100" value="30">

    You can provide an optional step:

    You can provide an optional step:

    <input type="range" name="age" min="0" max="100" value="30" step="10">

    Telephone (Telephone)

    The type="tel" input field is used to enter a phone number:

    The type="tel" input field is used to enter a phone number:

    <input type="tel" name="telephone-number">

    The main selling point for using tel over text is on mobile, where the device can choose to show a numeric keyboard.

    The main selling point for using tel over text is on mobile, where the device can choose to show a numeric keyboard.

    Specify a pattern attribute for additional validation:

    Specify a pattern attribute for additional validation:

    <input type="tel" pattern="[0-9]{3}-[0-9]{8}" name="telephone-number">

    URL (URL)

    The type="url" field is used to enter a URL.

    The type="url" field is used to enter a URL.

    <input type="url" name="website">

    You can validate it using the pattern attribute:

    You can validate it using the pattern attribute:

    <input type="url" name="website"  pattern="https://.*">

    The textarea tag (The textarea tag)

    The textarea element allows users to enter multi-line text. Compared to input, it requires an ending tag:

    The textarea element allows users to enter multi-line text. Compared to input , it requires an ending tag:

    <textarea></textarea>

    You can set the dimensions using CSS, but also using the rows and cols attributes:

    You can set the dimensions using CSS, but also using the rows and cols attributes:

    <textarea rows="20" cols="10"></textarea>

    As with the other form tags, the name attribute determines the name in the data sent to the server:

    As with the other form tags, the name attribute determines the name in the data sent to the server:

    <textarea name="article"></textarea>

    The select tag (The select tag)

    This tag is used to create a drop-down menu.

    This tag is used to create a drop-down menu.

    The user can choose one of the options available.

    The user can choose one of the options available.

    Each option is created using the option tag. You add a name to the select, and a value to each option:

    Each option is created using the option tag. You add a name to the select, and a value to each option:

    <select name="color">
        <option value="red">Red</option>
        <option value="yellow">Yellow</option>
    </select>

    You can set an option disabled:

    You can set an option disabled:

    <select name="color">
        <option value="red" disabled>Red</option>
        <option value="yellow">Yellow</option>
    </select>

    You can have one empty option:

    You can have one empty option:

    <select name="color">
        <option value="">None</option>
        <option value="red">Red</option>
        <option value="yellow">Yellow</option>
    </select>

    Options can be grouped using the optgroup tag. Each option group has a label attribute:

    Options can be grouped using the optgroup tag. Each option group has a label attribute:

    <select name="color">
        <optgroup label="Primary">
            <option value="red">Red</option>
            <option value="yellow">Yellow</option>
            <option value="blue">Blue</option>
        </optgroup>
        <optgroup label="Others">
            <option value="green">Green</option>
            <option value="pink">Pink</option>
        </optgroup>
    </select>

    TABLES (TABLES)

    In the early days of the web tables were a very important part of building layouts.

    In the early days of the web tables were a very important part of building layouts.

    Later on they were replaced by CSS and its layout capabilities, and today we have powerful tools like CSS Flexbox and CSS Grid to build layouts. Tables are now used just for, guess what, building tables!

    Later on they were replaced by CSS and its layout capabilities, and today we have powerful tools like CSS Flexbox and CSS Grid to build layouts. Tables are now used just for, guess what, building tables!

    The table tag (The table tag)

    You define a table using the table tag:

    You define a table using the table tag:

    <table>
    
    </table>

    Inside the table we'll define the data. We reason in terms of rows, which means we add rows into a table (not columns). We'll define columns inside a row.

    Inside the table we'll define the data. We reason in terms of rows, which means we add rows into a table (not columns). We'll define columns inside a row.

    Rows (Rows)

    A row is added using the tr tag, and that's the only thing we can add into a table element:

    A row is added using the tr tag, and that's the only thing we can add into a table element:

    <table>
      <tr></tr>
      <tr></tr>
      <tr></tr>
    </table>

    This is a table with 3 rows.

    This is a table with 3 rows.

    The first row can take the role of the header.

    The first row can take the role of the header.

    Column headers (Column headers)

    The table header contains the name of a column, typically in a bold font.

    The table header contains the name of a column, typically in a bold font.

    Think about an Excel / Google Sheets document. The top A-B-C-D... header.

    Think about an Excel / Google Sheets document. The top ABCD... header.

    We define the header using the th tag:

    We define the header using the th tag:

    <table>
      <tr>
        <th>Column 1</th>
        <th>Column 2</th>
        <th>Column 3</th>
      </tr>
      <tr></tr>
      <tr></tr>
    </table>

    The table content (The table content)

    The content of the table is defined using td tags, inside the other tr elements:

    The content of the table is defined using td tags, inside the other tr elements:

    <table>
      <tr>
        <th>Column 1</th>
        <th>Column 2</th>
        <th>Column 3</th>
      </tr>
      <tr>
        <td>Row 1 Column 1</td>
        <td>Row 1 Column 2</td>
        <td>Row 1 Column 3</td>
      </tr>
      <tr>
        <td>Row 2 Column 1</td>
        <td>Row 2 Column 2</td>
        <td>Row 2 Column 3</td>
      </tr>
    </table>

    This is how browsers render it, if you don't add any CSS styling:

    This is how browsers render it, if you don't add any CSS styling:

    Adding this CSS:

    Adding this CSS:

    th, td {
      padding: 10px;
      border: 1px solid #333;
    }

    makes the table look more like a proper table:

    makes the table look more like a proper table:

    Span columns and rows (Span columns and rows)

    A row can decide to span over 2 or more columns, using the colspan attribute:

    A row can decide to span over 2 or more columns, using the colspan attribute:

    <table>
      <tr>
        <th>Column 1</th>
        <th>Column 2</th>
        <th>Column 3</th>
      </tr>
      <tr>
        <td colspan="2">Row 1 Columns 1-2</td>
        <td>Row 1 Column 3</td>
      </tr>
      <tr>
        <td colspan="3">Row 2 Columns 1-3</td>
      </tr>
    </table>

    Or it can span over 2 or more rows, using the rowspan attribute:

    Or it can span over 2 or more rows, using the rowspan attribute:

    <table>
      <tr>
        <th>Column 1</th>
        <th>Column 2</th>
        <th>Column 3</th>
      </tr>
      <tr>
        <td colspan="2" rowspan="2">Rows 1-2 Columns 1-2</td>
        <td>Row 1 Column 3</td>
      </tr>
      <tr>
        <td>Row 2 Column 3</td>
      </tr>
    </table>

    Row headings (Row headings)

    Before I explained how you can have column headings, using the th tag inside the first tr tag of the table.

    Before I explained how you can have column headings, using the th tag inside the first tr tag of the table.

    You can add a th tag as the first element inside a tr that's not the first tr of the table, to have row headings:

    You can add a th tag as the first element inside a tr that's not the first tr of the table, to have row headings:

    <table>
      <tr>
        <th></th>
        <th>Column 2</th>
        <th>Column 3</th>
      </tr>
      <tr>
        <th>Row 1</th>
        <td>Col 2</td>
        <td>Col 3</td>
      </tr>
      <tr>
        <th>Row 2</th>
        <td>Col 2</td>
        <td>Col 3</td>
      </tr>
    </table>

    More tags to organize the table (More tags to organize the table)

    You can add 3 more tags into a table, to have it more organized.

    You can add 3 more tags into a table, to have it more organized.

    This is best when using big tables. And to properly define a header and a footer, too.

    This is best when using big tables. And to properly define a header and a footer, too.

    Those tags are

    Those tags are

    • thead

      thead

    • tbody

      tbody

    • tfoot

      tfoot

    They wrap the tr tags to clearly define the different sections of the table. Here's an example:

    They wrap the tr tags to clearly define the different sections of the table. 这是一个例子:

    <table>
      <thead>
        <tr>
          <th></th>
          <th>Column 2</th>
          <th>Column 3</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <th>Row 1</th>
          <td>Col 2</td>
          <td>Col 3</td>
        </tr>
        <tr>
          <th>Row 2</th>
          <td>Col 2</td>
          <td>Col 3</td>
        </tr>
      </tbody>
      <tfoot>
        <tr>
          <td></td>
          <td>Footer of Col 1</td>
          <td>Footer of Col 2</td>
        </tr>
      </tfoot>
    </table>

    Table caption (Table caption)

    A table should have a caption tag that describes its content. That tag should be put immediately after the opening table tag:

    A table should have a caption tag that describes its content. That tag should be put immediately after the opening table tag:

    <table>
      <caption>Dogs age</caption>
      <tr>
        <th>Dog</th>
        <th>Age</th>
      </tr>
      <tr>
        <td>Roger</td>
        <td>7</td>
      </tr>
    </table>

    MULTIMEDIA TAGS: AUDIO AND VIDEO (MULTIMEDIA TAGS: AUDIO AND VIDEO)

    In this section I want to show you the audio and video tags.

    In this section I want to show you the audio and video tags.

    The audio tag (The audio tag)

    This tag allows you to embed audio content in your HTML pages.

    This tag allows you to embed audio content in your HTML pages.

    This element can stream audio, maybe using a microphone via getUserMedia(), or it can play an audio source which you reference using the src attribute:

    This element can stream audio, maybe using a microphone via getUserMedia() , or it can play an audio source which you reference using the src attribute:

    <audio src="file.mp3">

    By default the browser does not show any controls for this element. Which means the audio will play only if set to autoplay (more on this later) and the user can't see how to stop it or control the volume or move through the track.

    By default the browser does not show any controls for this element. Which means the audio will play only if set to autoplay (more on this later) and the user can't see how to stop it or control the volume or move through the track.

    To show the built-in controls, you can add the controls attribute:

    To show the built-in controls, you can add the controls attribute:

    <audio src="file.mp3" controls>

    Controls can have a custom skin.

    Controls can have a custom skin.

    You can specify the MIME type of the audio file using the type attribute. If not set, the browser will try to automatically determine it:

    You can specify the MIME type of the audio file using the type attribute. If not set, the browser will try to automatically determine it:

    <audio src="file.mp3" controls type="audio/mpeg">

    An audio file by default does not play automatically. Add the autoplay attribute to play the audio automatically:

    An audio file by default does not play automatically. Add the autoplay attribute to play the audio automatically:

    <audio src="file.mp3" controls autoplay>

    Note: mobile browsers don't allow autoplay

    Note: mobile browsers don't allow autoplay

    The loop attribute restarts the audio playing at 0:00 if set; otherwise, if not present, the audio stops at the end of the file:

    The loop attribute restarts the audio playing at 0:00 if set; otherwise, if not present, the audio stops at the end of the file:

    <audio src="file.mp3" controls autoplay loop>

    You can also play an audio file muted using the muted attribute (not really sure what's the usefulness of this):

    You can also play an audio file muted using the muted attribute (not really sure what's the usefulness of this):

    <audio src="file.mp3" controls autoplay loop muted>

    Using JavaScript you can listen for various events happening on an audio element, the most basic of which are:

    Using JavaScript you can listen for various events happening on an audio element, the most basic of which are:

    • play when the file starts playing

      play when the file starts playing

    • pause when the audio playing was paused

      pause when the audio playing was paused

    • playing when the audio is resumed from a pause

      playing when the audio is resumed from a pause

    • ended when the end of the audio file was reached

      ended when the end of the audio file was reached

    The video tag (The video tag)

    This tag allows you to embed video content in your HTML pages.

    This tag allows you to embed video content in your HTML pages.

    This element can stream video, using a webcam via getUserMedia() or WebRTC, or it can play a video source which you reference using the src attribute:

    This element can stream video, using a webcam via getUserMedia() or WebRTC , or it can play a video source which you reference using the src attribute:

    <video src="file.mp4">

    By default the browser does not show any controls for this element, just the video.

    By default the browser does not show any controls for this element, just the video.

    Which means the video will play only if set to autoplay (more on this later) and the user can't see how to stop it, pause it, control the volume or skip to a specific position in the video.

    Which means the video will play only if set to autoplay (more on this later) and the user can't see how to stop it, pause it, control the volume or skip to a specific position in the video.

    To show the built-in controls, you can add the controls attribute:

    To show the built-in controls, you can add the controls attribute:

    <video src="file.mp4" controls>

    Controls can have a custom skin.

    Controls can have a custom skin.

    You can specify the MIME type of the video file using the type attribute. If not set, the browser will try to automatically determine it:

    You can specify the MIME type of the video file using the type attribute. If not set, the browser will try to automatically determine it:

    <video src="file.mp4" controls type="video/mp4">

    A video file by default does not play automatically. Add the autoplay attribute to play the video automatically:

    A video file by default does not play automatically. Add the autoplay attribute to play the video automatically:

    <video src="file.mp4" controls autoplay>

    Some browsers also require the muted attribute to autoplay. The video autoplays only if muted:

    Some browsers also require the muted attribute to autoplay. The video autoplays only if muted:

    <audio src="file.mp3" controls autoplay muted>

    The loop attribute restarts the video playing at 0:00 if set; otherwise, if not present, the video stops at the end of the file:

    The loop attribute restarts the video playing at 0:00 if set; otherwise, if not present, the video stops at the end of the file:

    <video src="file.mp4" controls autoplay loop>

    You can set an image to be the poster image:

    You can set an image to be the poster image:

    <video src="file.mp4" poster="picture.png">

    If not present, the browser will display the first frame of the video as soon as it's available.

    If not present, the browser will display the first frame of the video as soon as it's available.

    You can set the width and height attributes to set the space that the element will take so that the browser can account for it and it does not change the layout when it's finally loaded. It takes a numeric value, expressed in pixels.

    You can set the width and height attributes to set the space that the element will take so that the browser can account for it and it does not change the layout when it's finally loaded. It takes a numeric value, expressed in pixels.

    Using JavaScript you can listen for various events happening on an video element, the most basic of which are:

    Using JavaScript you can listen for various events happening on an video element, the most basic of which are:

    • play when the file starts playing

      play when the file starts playing

    • pause when the video was paused

      pause when the video was paused

    • playing when the video is resumed from a pause

      playing when the video is resumed from a pause

    • ended when the end of the video file was reached

      ended when the end of the video file was reached

    IFRAMES (IFRAMES)

    The iframe tag allows us to embed content coming from other origins (other sites) into our web page.

    The iframe tag allows us to embed content coming from other origins (other sites) into our web page.

    Technically, an iframe creates a new nested browsing context. This means that anything in the iframe does not interfere with the parent page, and vice versa. JavaScript and CSS do not "leak" to/from iframes.

    Technically, an iframe creates a new nested browsing context. This means that anything in the iframe does not interfere with the parent page, and vice versa. JavaScript and CSS do not "leak" to/from iframes.

    Many sites use iframes to perform various things. You might be familiar with Codepen, Glitch or other sites that allow you to code in one part of the page, and you see the result in a box. That's an iframe.

    Many sites use iframes to perform various things. You might be familiar with Codepen, Glitch or other sites that allow you to code in one part of the page, and you see the result in a box. That's an iframe.

    You create one this way:

    You create one this way:

    <iframe src="page.html"></iframe>

    You can load an absolute URL, too:

    You can load an absolute URL, too:

    <iframe src="https://site.com/page.html"></iframe>

    You can set a set of width and height parameters (or set them using CSS) otherwise the iframe will use the defaults, a 300x150 pixels box:

    You can set a set of width and height parameters (or set them using CSS) otherwise the iframe will use the defaults, a 300x150 pixels box:

    <iframe src="page.html" width="800" height="400"></iframe>

    Srcdoc (Srcdoc)

    The srcdoc attribute lets you specify some inline HTML to show. It's an alternative to src, but recent and not supported in Edge 18 and lower, and in IE:

    The srcdoc attribute lets you specify some inline HTML to show. It's an alternative to src , but recent and not supported in Edge 18 and lower, and in IE:

    <iframe srcdoc="<p>My dog is a good dog</p>"></iframe>

    Sandbox (Sandbox)

    The sandbox attribute allows us to limit the operations allowed in the iframes.

    The sandbox attribute allows us to limit the operations allowed in the iframes.

    If we omit it, everything is allowed:

    If we omit it, everything is allowed:

    <iframe src="page.html"></iframe>

    If we set it to "", nothing is allowed:

    If we set it to "", nothing is allowed:

    <iframe src="page.html" sandbox=""></iframe>

    We can select what to allow by adding options in the sandbox attribute. You can allow multiple ones by adding a space in between. Here's an incomplete list of the options you can use:

    We can select what to allow by adding options in the sandbox attribute. You can allow multiple ones by adding a space in between. Here's an incomplete list of the options you can use:

    • allow-forms: allow to submit forms

      allow-forms : allow to submit forms

    • allow-modals allow to open modals windows, including calling alert() in JavaScript

      allow-modals allow to open modals windows, including calling alert() in JavaScript

    • allow-orientation-lock allow to lock the screen orientation

      allow-orientation-lock allow to lock the screen orientation

    • allow-popups allow popups, using window.open() and target="_blank" links

      allow-popups allow popups, using window.open() and target="_blank" links

    • allow-same-origin treat the resource being loaded as same origin

      allow-same-origin treat the resource being loaded as same origin

    • allow-scripts lets the loaded iframe run scripts (but not create popups).

      allow-scripts lets the loaded iframe run scripts (but not create popups).

    • allow-top-navigation gives access to the iframe to the top level browsing context

      allow-top-navigation gives access to the iframe to the top level browsing context

    Allow (Allow)

    Currently experimental and only supported by Chromium-based browsers, this is the future of resource sharing between the parent window and the iframe.

    Currently experimental and only supported by Chromium-based browsers, this is the future of resource sharing between the parent window and the iframe.

    It's similar to the sandbox attribute, but lets us allow specific features, including:

    It's similar to the sandbox attribute, but lets us allow specific features, including:

    • accelerometer gives access to the Sensors API Accelerometer interface

      accelerometer gives access to the Sensors API Accelerometer interface

    • ambient-light-sensor gives access to the Sensors API AmbientLightSensor interface

      ambient-light-sensor gives access to the Sensors API AmbientLightSensor interface

    • autoplay allows to autoplay video and audio files

      autoplay allows to autoplay video and audio files

    • camera allows to access the camera from the getUserMedia API

      camera allows to access the camera from the getUserMedia API

    • display-capture allows to access the screen content using the getDisplayMedia API

      display-capture allows to access the screen content using the getDisplayMedia API

    • fullscreen allows to access fullscreen mode

      fullscreen allows to access fullscreen mode

    • geolocation allows to access the Geolocation API

      geolocation allows to access the Geolocation API

    • gyroscope gives access to the Sensors API Gyroscope interface

      gyroscope gives access to the Sensors API Gyroscope interface

    • magnetometer gives access to the Sensors API Magnetometer interface

      magnetometer gives access to the Sensors API Magnetometer interface

    • microphone gives access to the device microphone using the getUserMedia API

      microphone gives access to the device microphone using the getUserMedia API

    • midi allows access to the Web MIDI API

      midi allows access to the Web MIDI API

    • payment gives access to the Payment Request API

      payment gives access to the Payment Request API

    • speaker allows access to playing audio through the device speakers

      speaker allows access to playing audio through the device speakers

    • usb gives access to the WebUSB API.

      usb gives access to the WebUSB API.

    • vibrate gives access to the Vibration API

      vibrate gives access to the Vibration API

    • vr gives access to the WebVR API

      vr gives access to the WebVR API

    Referrer (Referrer)

    When loading an iframe, the browser sends it important information about who is loading it in the Referer header (notice the single r, a typo we must live with).

    When loading an iframe, the browser sends it important information about who is loading it in the Referer header (notice the single r , a typo we must live with).

    The misspelling of referrer originated in the original proposal by computer scientist Phillip Hallam-Baker to incorporate the field into the HTTP specification. The misspelling was set in stone by the time of its incorporation into the Request for Comments standards document RFC 1945

    The misspelling of referrer originated in the original proposal by computer scientist Phillip Hallam-Baker to incorporate the field into the HTTP specification. The misspelling was set in stone by the time of its incorporation into the Request for Comments standards document RFC 1945

    The referrerpolicy attribute lets us set the referrer to send to the iframe when loading it. The referrer is an HTTP header that lets the page know who is loading it. These are the allowed values:

    The referrerpolicy attribute lets us set the referrer to send to the iframe when loading it. The referrer is an HTTP header that lets the page know who is loading it. These are the allowed values:

    • no-referrer-when-downgrade it's the default, and does not send the referrer when the current page is loaded over HTTPS and the iframe loads on the HTTP protocol

      no-referrer-when-downgrade it's the default, and does not send the referrer when the current page is loaded over HTTPS and the iframe loads on the HTTP protocol

    • no-referrer does not send the referrer header

      no-referrer does not send the referrer header

    • origin the referrer is sent, and only contains the origin (port, protocol, domain), not the origin + path which is the default

      origin the referrer is sent, and only contains the origin (port, protocol, domain), not the origin + path which is the default

    • origin-when-cross-origin when loading from the same origin (port, protocol, domain) in the iframe, the referrer is sent in its complete form (origin + path). Otherwise only the origin is sent

      origin-when-cross-origin when loading from the same origin (port, protocol, domain) in the iframe, the referrer is sent in its complete form (origin + path). Otherwise only the origin is sent

    • same-origin the referrer is sent only when loading from the same origin (port, protocol, domain) in the iframe

      same-origin the referrer is sent only when loading from the same origin (port, protocol, domain) in the iframe

    • strict-origin sends the origin as the referrer if the current page is loaded over HTTPS and the iframe also loads on the HTTPS protocol. Sends nothing if the iframe is loaded over HTTP

      strict-origin sends the origin as the referrer if the current page is loaded over HTTPS and the iframe also loads on the HTTPS protocol. Sends nothing if the iframe is loaded over HTTP

    • strict-origin-when-cross-origin sends the origin + path as the referrer when working on the same origin. Sends the origin as the referrer if the current page is loaded over HTTPS and the iframe also loads on the HTTPS protocol. Sends nothing if the iframe is loaded over HTTP

      strict-origin-when-cross-origin sends the origin + path as the referrer when working on the same origin. Sends the origin as the referrer if the current page is loaded over HTTPS and the iframe also loads on the HTTPS protocol. Sends nothing if the iframe is loaded over HTTP

    • unsafe-url: sends the origin + path as the referrer even when loading resources from HTTP and the current page is loaded over HTTPS

      unsafe-url : sends the origin + path as the referrer even when loading resources from HTTP and the current page is loaded over HTTPS

    IMAGES (IMAGES)

    Images can be displayed using the img tag.

    Images can be displayed using the img tag.

    This tag accepts a src attribute, which we use to set the image source:

    This tag accepts a src attribute, which we use to set the image source:

    <img src="image.png">

    We can use a wide set of images. The most common ones are PNG, JPEG, GIF, SVG and more recently WebP.

    We can use a wide set of images. The most common ones are PNG, JPEG, GIF, SVG and more recently WebP.

    The HTML standard requires an alt attribute to be present, to describe the image. This is used by screen readers and also by search engine bots:

    The HTML standard requires an alt attribute to be present, to describe the image. This is used by screen readers and also by search engine bots:

    <img src="dog.png" alt="A picture of a dog">

    You can set the width and height attributes to set the space that the element will take, so that the browser can account for it and it does not change the layout when it's fully loaded. It takes a numeric value, expressed in pixels.

    You can set the width and height attributes to set the space that the element will take, so that the browser can account for it and it does not change the layout when it's fully loaded. It takes a numeric value, expressed in pixels.

    <img src="dog.png" alt="A picture of a dog" width="300" height="200">

    The figure tag (The figure tag)

    The figure tag is often used along with the img tag.

    The figure tag is often used along with the img tag.

    figure is a semantic tag often used when you want to display an image with a caption. You use it like this:

    figure is a semantic tag often used when you want to display an image with a caption. You use it like this:

    <figure>
        <img src="dog.png"
             alt="A nice dog">
        <figcaption>A nice dog</figcaption>
    </figure>

    The figcaption tag wraps the caption text.

    The figcaption tag wraps the caption text.

    Responsive images using srcset (Responsive images using srcset)

    The srcset attribute allows you to set responsive images that the browser can use depending on the pixel density or window width, according to your preferences. This way, it can only download the resources it needs to render the page, without downloading a bigger image if it's on a mobile device, for example.

    The srcset attribute allows you to set responsive images that the browser can use depending on the pixel density or window width, according to your preferences. This way, it can only download the resources it needs to render the page, without downloading a bigger image if it's on a mobile device, for example.

    Here's an example, where we give 4 additional images for 4 different screen sizes:

    Here's an example, where we give 4 additional images for 4 different screen sizes:

    <img src="dog.png"
        alt="A picture of a dog"
        srcset="dog-500.png 500w,
                   dog-800.png 800w,
                 dog-1000.png 1000w,
                 dog-1400.png 1400w">

    In the srcset we use the w measure to indicate the window width.

    In the srcset we use the w measure to indicate the window width.

    Since we do so, we also need to use the sizes attribute:

    Since we do so, we also need to use the sizes attribute:

    <img src="dog.png"
        alt="A picture of a dog"
        sizes="(max-width: 500px) 100vw, (max-width: 900px) 50vw, 800px"
        srcset="dog-500.png 500w,
                   dog-800.png 800w,
                 dog-1000.png 1000w,
                 dog-1400.png 1400w">

    In this example the (max-width: 500px) 100vw, (max-width: 900px) 50vw, 800px string in the sizes attribute describes the size of the image in relation to the viewport, with multiple conditions separated by a semicolon.

    In this example the (max-width: 500px) 100vw, (max-width: 900px) 50vw, 800px string in the sizes attribute describes the size of the image in relation to the viewport, with multiple conditions separated by a semicolon.

    The media condition max-width: 500px sets the size of the image in correlation to the viewport width. In short, if the window size is < 500px, it renders the image at 100% of the window size.

    The media condition max-width: 500px sets the size of the image in correlation to the viewport width. In short, if the window size is < 500px, it renders the image at 100% of the window size.

    If the window size is bigger but < 900px, it renders the image at 50% of the window size.

    If the window size is bigger but < 900px , it renders the image at 50% of the window size.

    And if even bigger, it renders the image at 800px.

    And if even bigger, it renders the image at 800px.

    The vw unit of measure can be new to you, and in short we can say that 1 vw is 1% of the window width, so 100vw is 100% of the window width.

    The vw unit of measure can be new to you, and in short we can say that 1 vw is 1% of the window width, so 100vw is 100% of the window width.

    A useful website to generate the srcset and progressively smaller images is https://responsivebreakpoints.com/.

    A useful website to generate the srcset and progressively smaller images is https://responsivebreakpoints.com/ .

    The picture tag (The picture tag)

    HTML also gives us the picture tag, which does a very similar job to srcset, and the differences are very subtle.

    HTML also gives us the picture tag, which does a very similar job to srcset , and the differences are very subtle.

    You use picture when instead of just serving a smaller version of a file, you completely want to change it. Or serve a different image format.

    You use picture when instead of just serving a smaller version of a file, you completely want to change it. Or serve a different image format.

    The best use case I found is when serving a WebP image, which is a format still not widely supported. In the picture tag you specify a list of images, and they will be used in order, so in the next example, browsers that support WebP will use the first image, and fallback to JPG if not:

    The best use case I found is when serving a WebP image, which is a format still not widely supported. In the picture tag you specify a list of images, and they will be used in order, so in the next example, browsers that support WebP will use the first image, and fallback to JPG if not:

    <picture>
      <source type="image/webp" srcset="image.webp">
      <img src="image.jpg" alt="An image">
    </picture>

    The source tag defines one (or more) formats for the images. The img tag is the fallback in case the browser is very old and does not support the picture tag.

    The source tag defines one (or more) formats for the images. The img tag is the fallback in case the browser is very old and does not support the picture tag.

    In the source tag inside picture you can add a media attribute to set media queries.

    In the source tag inside picture you can add a media attribute to set media queries.

    The example that follows kind of works like the above example with srcset:

    The example that follows kind of works like the above example with srcset :

    <picture>
      <source media="(min-width: 500w)" srcset="dog-500.png" sizes="100vw">
      <source media="(min-width: 800w)" srcset="dog-800.png" sizes="100vw">
      <source media="(min-width: 1000w)" srcset="dog-1000.png"    sizes="800px">
      <source media="(min-width: 1400w)" srcset="dog-1400.png"    sizes="800px">
      <img src="dog.png" alt="A dog image">
    </picture>

    But that's not its use case, because as you can see it's much more verbose.

    But that's not its use case, because as you can see it's much more verbose.

    The picture tag is recent but is now supported by all the major browsers except Opera Mini and IE (all versions).

    The picture tag is recent but is now supported by all the major browsers except Opera Mini and IE (all versions).

    ACCESSIBILITY (ACCESSIBILITY)

    It's important we design our HTML with accessibility in mind.

    It's important we design our HTML with accessibility in mind.

    Having accessible HTML means that people with disabilities can use the Web. There are totally blind or visually impaired users, people with hearing loss issues and a multitude of other different disabilities.

    Having accessible HTML means that people with disabilities can use the Web. There are totally blind or visually impaired users, people with hearing loss issues and a multitude of other different disabilities.

    Unfortunately this topic does not take the importance it needs, and it doesn't seem as cool as others.

    Unfortunately this topic does not take the importance it needs, and it doesn't seem as cool as others.

    What if a person can't see your page, but still wants to consume its content? First, how do they do that? They can't use the mouse, they use something called a screen reader. You don't have to imagine that. You can try one now: Google provides the free ChromeVox Chrome Extension. Accessibility must also take care of allowing tools to easily select elements or navigate through the pages.

    What if a person can't see your page, but still wants to consume its content? First, how do they do that? They can't use the mouse, they use something called a screen reader . You don't have to imagine that. You can try one now: Google provides the free ChromeVox Chrome Extension . Accessibility must also take care of allowing tools to easily select elements or navigate through the pages.

    Web pages and Web apps are not always built with accessibility as one of their first goals, and maybe version 1 is released not accessible but it's possible to make a web page accessible after the fact. Sooner is better, but it's never too late.

    Web pages and Web apps are not always built with accessibility as one of their first goals, and maybe version 1 is released not accessible but it's possible to make a web page accessible after the fact. Sooner is better, but it's never too late.

    It's important and in my country, websites built by the government or other public organizations must be accessible.

    It's important and in my country, websites built by the government or other public organizations must be accessible.

    What does this mean to make an HTML accessible? Let me illustrate the main things you need to think about.

    What does this mean to make an HTML accessible? Let me illustrate the main things you need to think about.

    Note: there are several other things to take care about, which might go in the CSS topic, like colors, contrast and fonts. Or how to make SVG images accessible. I don't talk about them here.

    Note: there are several other things to take care about, which might go in the CSS topic, like colors, contrast and fonts. Or how to make SVG images accessible . I don't talk about them here.

    Use semantic HTML (Use semantic HTML)

    Semantic HTML is very important and it's one of the main things you need to take care of. Let me illustrate a few common scenarios.

    Semantic HTML is very important and it's one of the main things you need to take care of. Let me illustrate a few common scenarios.

    It's important to use the correct structure for heading tags. The most important is h1, and you use higher numbers for less important ones, but all the same-level headings should have the same meaning (think about it like a tree structure)

    It's important to use the correct structure for heading tags. The most important is h1 , and you use higher numbers for less important ones, but all the same-level headings should have the same meaning (think about it like a tree structure)

    h1
        h2
            h3
        h2
        h2
            h3
                h4

    Use strong and em instead of b and i. Visually they look the same, but the first 2 have more meaning associated with them. b and i are more visual elements.

    Use strong and em instead of b and i . Visually they look the same, but the first 2 have more meaning associated with them. b and i are more visual elements.

    Lists are important. A screen reader can detect a list and provide an overview, then let the user choose to get into the list or not.

    Lists are important. A screen reader can detect a list and provide an overview, then let the user choose to get into the list or not.

    A table should have a caption tag that describes its content:

    A table should have a caption tag that describes its content:

    <table>
      <caption>Dogs age</caption>
      <tr>
        <th>Dog</th>
        <th>Age</th>
      </tr>
      <tr>
        <td>Roger</td>
        <td>7</td>
      </tr>
    </table>

    Use alt attributes for images (Use alt attributes for images)

    All images must have an alt tag describing the image content. It's not just a good practice, it's required by the HTML standard and your HTML without it is not validated.

    All images must have an alt tag describing the image content. It's not just a good practice, it's required by the HTML standard and your HTML without it is not validated.

    <img src="dog.png" alt="picture of my dog">

    It's also good for search engines, if that's an incentive for you to add it.

    It's also good for search engines, if that's an incentive for you to add it.

    Use the role attribute (Use the role attribute)

    The role attribute lets you assign specific roles to the various elements in your page.

    The role attribute lets you assign specific roles to the various elements in your page.

    You can assign lots of different roles: complementary, list, listitem, main, navigation, region, tab, alert, application, article, banner, button, cell, checkbox, contentinfo, dialog, document, feed, figure, form, grid, gridcell, heading, img, listbox, row, rowgroup, search, switch, table, tabpanel, textbox, timer.

    You can assign lots of different roles: complementary, list, listitem, main, navigation, region, tab, alert, application, article, banner, button, cell, checkbox, contentinfo, dialog, document, feed, figure, form, grid, gridcell, heading, img, listbox, row, rowgroup, search, switch, table, tabpanel, textbox, timer.

    It's a lot and for the full reference of each of them I give you this MDN link. But you don't need to assign a role to every element in the page. Screen readers can infer from the HTML tag in most cases. For example you don't need to add a role tag to semantic tags like nav, button, form.

    It's a lot and for the full reference of each of them I give you this MDN link . But you don't need to assign a role to every element in the page. Screen readers can infer from the HTML tag in most cases. For example you don't need to add a role tag to semantic tags like nav , button , form .

    Let's take the nav tag example. You can use it to define the page navigation like this:

    Let's take the nav tag example. You can use it to define the page navigation like this:

    <nav>
      <ul>
        <li><a href="/">Home</a></li>
        <li><a href="/blog">Blog</a></li>
      </ul>
    </nav>

    If you were forced to use a div tag instead of nav, you'd use the navigation role:

    If you were forced to use a div tag instead of nav , you'd use the navigation role:

    <div role="navigation">
      <ul>
        <li><a href="/">Home</a></li>
        <li><a href="/blog">Blog</a></li>
      </ul>
    </div>

    So here you got a practical example: role is used to assign a meaningful value when the tag does not convey the meaning already.

    So here you got a practical example: role is used to assign a meaningful value when the tag does not convey the meaning already.

    Use the tabindex attribute (Use the tabindex attribute)

    The tabindex attribute allows you to change the order of how pressing the Tab key selects "selectable" elements. By defaults only links and form elements are "selectable" by navigation using the Tab key (and you don't need to set tabindex on them).

    The tabindex attribute allows you to change the order of how pressing the Tab key selects "selectable" elements. By defaults only links and form elements are "selectable" by navigation using the Tab key (and you don't need to set tabindex on them).

    Adding tabindex="0" makes an element selectable:

    Adding tabindex="0" makes an element selectable:

    <div tabindex="0">
    ...
    </div>

    Using tabindex="-1" instead removes an element from this tab-based navigation, and it can be pretty useful.

    Using tabindex="-1" instead removes an element from this tab-based navigation, and it can be pretty useful.

    Use the aria attributes (Use the aria attributes)

    ARIA is an acronym that means Accessible Rich Internet Applications and defines semantics that can be applied to elements.

    ARIA is an acronym that means Accessible Rich Internet Applications and defines semantics that can be applied to elements.

    aria-label (aria-label)

    This attribute is used to add a string to describe an element.

    This attribute is used to add a string to describe an element.

    Example:

    例:

    <p aria-label="The description of the product">...</p>

    I use this attribute on my blog sidebar, where I have an input box for search without an explicit label, as it has a placeholder attribute.

    I use this attribute on my blog sidebar, where I have an input box for search without an explicit label, as it has a placeholder attribute.

    aria-labelledby (aria-labelledby)

    This attribute sets a correlation between the current element and the one that labels it.

    This attribute sets a correlation between the current element and the one that labels it.

    If you know how an input element can be associated to a label element, that's similar.

    If you know how an input element can be associated to a label element, that's similar.

    We pass the item id that describes the current element.

    We pass the item id that describes the current element.

    Example:

    例:

    <h3 id="description">The description of the product</h3>
    
    <p aria-labelledby="description">
    ...
    </p>

    aria-describedby (aria-describedby)

    This attribute lets us associate an element with another element that serves as description.

    This attribute lets us associate an element with another element that serves as description.

    Example:

    例:

    <button aria-describedby="payNowDescription" >Pay now</button>
    
    <div id="payNowDescription">Clicking the button will send you to our Stripe form!</div>

    Use aria-hidden to hide content (Use aria-hidden to hide content)

    I like a minimalistic design in my sites. My blog for example is mostly just content, with some links in the sidebar. But some things in the sidebar are just visual elements that don't add up to the experience of a person that can't see the page. Like my logo picture, or the dark/bright theme selector.

    I like a minimalistic design in my sites. My blog for example is mostly just content, with some links in the sidebar. But some things in the sidebar are just visual elements that don't add up to the experience of a person that can't see the page. Like my logo picture, or the dark/bright theme selector.

    Adding the aria-hidden="true" attribute will tell screen readers to ignore that element.

    Adding the aria-hidden="true" attribute will tell screen readers to ignore that element.

    Where to learn more (Where to learn more)

    This is just an introduction to the topic. To learn more, I recommend these resources:

    This is just an introduction to the topic. To learn more, I recommend these resources:



    You reached the end of the HTML Handbook.

    You reached the end of the HTML Handbook.

    Click here to get a PDF / ePub / Mobi version of this book to read offline!

    Click here to get a PDF / ePub / Mobi version of this book to read offline !

    翻译自: https://www.freecodecamp.org/news/the-html-handbook/

    html手册

    展开全文
  • MIDI文件格式分析

    千次阅读 2008-01-25 12:24:00
    MIDI文件属于二进制文件,这种文件一般都有如下基本结构: 文件头+数据描述文件头一般包括文件的类型,因为Midi文件仅以.mid为扩展名的就有0类和1类两种,而大家熟悉的位图文件的格式就更多了,所以才会出现文件头...

    MIDI文件属于二进制文件,这种文件一般都有如下基本结构: 文件头+数据描述

    文件头一般包括文件的类型,因为Midi文件仅以.mid为扩展名的就有0类和1类两种,而大家熟悉的位图文件的格式就更多了,所以才会出现文件头这种东西。

    而数据描述部份是主体,我们现在来一起分析它的结构:

    在每个Midi文件的开头都有如下内容,它们的十六进制代码为:“4d 54 68 64 00 00 00 06 ff ff nn nn dd dd”。

    前四个是ASCII字符“MThd”是用来鉴别是否Midi文件,而随后的四个字节是指明文件头描述部分的字节数,它总是6,所以一定是“00 00 00 06”,以下是剩余部分的含义:

    以上就是MIDI文件头了,后面的所有内容都是真正做事的,我们先来看看它的构成。

    MIDI的数据是由若干个格式相同的子数据构成的,这些子数据在多音轨的格式中记录了一个轨道的所有信息。多加一个音轨,就简单地把数据追加在前一音轨的后面就可以了,不过不要忘记更改文件头中的nn nn(轨道数)

    先看全局音轨。全局音轨包括歌曲的附加信息(比如标题和版权)、歌曲速度和系统码(Sysx)等内容。

    不管是全局音轨还是含有音符的音轨,都以“4D 54 72 6B”开头,它其实是ASCII字符“MTrk”,其后跟着一个4个字节的整数,它标志了该轨道的字节数,这不包括前面的4个字节和本身的4个字节。这一点,我们可以在后面的例子中去理解。

    接着就是记录数据的地方了,每一个数据有着相同的结构:时间差+事件。

    所谓时间差,指的是前一个事件到该事件的时间数,它的单位是tick(MIDI的最小时间单位)。它的构成比较特殊,这里要用二进制来说明。

    一个字节有8位,如果仅使用7位,它可以表示0~127这128个数,而剩下的一位,则用来作为标志。如果要表示的数在以上范围,则这个标志为0,这时,一个7位的字节可以表示0~127tick。如果要表示的数超出了这个范围(比如240),则把标志设置成1,然后记录下高7位,剩下的留给下一个字节,在该例中240可以分解成128*1+112,这里的1就是第一个字节要记录的,加上标志位,应该为10000001,即十六进制的81;而112是下一个字节记录的,它的十六进制为70:所以要表示240这个时间,要写成81 70。同理,如果要表示65535tick,则可以先计算出65535=1282*3+1281*127+1280*127,然后得出结果:83 FF 7F。由此,我们反过来也可以知道如何确定时间差:只要标志位为0,则表示结束读取时间差。比如82 C0 03表示1282*2+1281*64+1280*3=40963,如果基本时间为120,则有341:043个四分音符。

    以这种方式记录整数的字节称为动态字节,它根据记录的整数改变自身的长度,这在后面还要用到,所以必须熟练计算。

    看完了这么麻烦的东西,我们再来看个更麻烦的东西:事件。在这些标准的解释后面,我们会通过一些例子来进一步掌握这些内容。

    事件大体上可以分为音符、控制器和系统信息这几个种类。对于这些事件,都有统一的表达结构:种类+参数。

    对于一个音符,由于它的有效范围是0~127,所以直接用00~7F作为“种类”,可以认为是个音符,比如3C表示中央C。而一个音符的最重要的参数是力度(也叫速度:velocity)。比如,3C 64 表示一个力度为十进制100的中央C音符。

    因为一个字节有8位,所以剩余的一位如果置1,再联合其他的7位,则可以表示各种信息。我们暂且无视一个音轨到底是全局的还是用于记录音符的。它们归根结底都是用来记录各种事件的,只不过有些应出现在全局音轨比较合乎逻辑而已。既然这样,我们就可以从下面的表来看事件:

    下表中,x表示音轨0~F,比如81表示松开第二轨的音符。

    下表详细地列出了FF的详细情况,对于字节数由数据决定的情况,表中以“--”表示。

    这些就是MIDI结构的全部内容,在下一讲,我们将通过一个实例来分析。

    要书写二进制(十六进制)文件,应该准备好一些工具,比如我自己用的是VC++,因为学习MIDI格式无非是想写它的软件,既然VC++可以编辑二进制文件,就将就着用吧。其次,应该找个可以编辑和播放MIDI文件的软件,比如Cakewalk,这样就可以开始了。

    首先书写文件头“4d 54 68 64 00 00 00 06”,我们直接写同步多音轨的格式,先写1个音轨,并以120为一个音符的基本时间。这样,随后的字节是:“00 01 00 01 00 78”。

    现在,如果用Cakewalk打开会失败,因为我们指定的音轨数为1,但是并没有书写任何音轨,如果改成“00 01 00 00 00 78”再打开,就不会出问题了。所以,今后如果更改了音轨数,千万不要忘记向“上头”汇报。

    把轨道数改回01,继续我们的实验。先写音轨的头信息:“4D 54 72 6B”(MTrk),因为我们还不能确定后面有多少字节,所以先把它假设成“00 00 00 00”,以后再回来改。

    我们先尝试设置歌曲的速度和节拍等基本信息。假设一个四分音符的时间是半秒,即0.5*106微秒。它的十六进制数是07A120,再看事件表,设置速度是51,但是在其前面必须是FF,然后它须要3个字节作为参数,因此字节数为03,参数为“07 A1 20”,也就是“FF 51 03 07 A1 20”。这是事件部分,不要忘记在其之前有个参数——时间差。这是一开始就应该设置的参数,因此时间差为00。所以,完整的事件应该是“00 FF 51 03 07 A1 20”,我们把这一段追加在Midi文件末尾。

    这时先不要急着用Cakewalk验证,因为我们还没有向“上级”报告,没错,把前面表示字节数的“00 00 00 00”改成“00 00 00 07”,如果用VC++作为二进制文件的编辑器,选择了事件后,可以在状态栏看到选择的字节长。保存后,再用Cakewalk打开,就可以看见速度是120。

    我们再来设置节拍和调号,因为一般用Cakewalk新建一个Midi会默认地设置成4/4,C大调,我们就改设成6/8,A大调。查阅事件表知道,58和59是分别用来设置节拍和调号的。虽然设置节拍的参数很多,但在现在的系统中,后两个参数是被忽略的,而且Cakewalk还会对其进行修正。因此,我们只要设置好实际有用的就可以了。分子是6,分母是8,所以第一个参数是06,第二个参数是03(23=8)。最后,补上前面的时间差和后面的两个被忽略的参数,它应该是“00 FF 58 04 06 03 00 00”;再看调号,A调有3个升号,因此可以这样的事件可以表示为“00 FF 59 02 03 00”。事实上,大小调是个被忽略的参数。我们统计一下至今为止事件的字节数,然后更改前面的参数,即把“00 00 00 07”改成“00 00 00 15”。保存后用Cakewalk打开,再进入五线谱窗口,就可以马上验证了。细心的你可能已经发现,进入五线谱窗口前和平常有些延迟,这是因为我们并没有设置好那些可以忽略的字节,而Cakewalk就是在对其进行重新验证,这一点,我们以后再讨论。

    用同样的方法,您可以很容易地设置歌曲的标题和版权,这作为一个练习,在这里就不多写了。我们现在学习写一个含有音符的轨道。首先您应该知道要做哪些事:1、写新音轨的信息头;2、向上级汇报多了一个音轨。接下来,我们开始写入一个简单的音符。

    假设向第一拍写一个中音A,这里可能要先说明一下,音符是从C0开始一起向上数的,数到中央C(C5)是十六进制的3C,则中音A应该为45,在附件中有详细的计算方法。我们知道在音乐中一个音符通常有三个属性:音高、力度和时值。可是我们在事件表中并没有看见有什么可以直接设置音符时值的标志。不错,事实上,音符的时值是由按下的时间和松开的时间决定的。我们假设要写入一个八分音符。它的Tick数是四分音符的一半,即60,十六进制表示成3C。我们先来看看与音符有关的标志。

    在事件表中,9x是用来打开一个音符,我们这里假设使用第7个通道(注意到MIDI有16个通道(Channel),而第10个被默认地用作打击乐,所以,我们在这个阶段(没有学习Sysx之前),先不要使用第10个通道),则9x中的x是6;再看它的参数,一个是音符,这里我们写入45,第二个是力度,我们用70,因为是一开始就触发的,所以前面的时间差还是00。这样我们就在第5个通道以力度112按下了一个中音A。对应的字节描述是“00 96 45 70”。它的时值不用想都知道一定是0,这取决于什么时候把它松开。

    特别地,如果一个音符的力度为0,则MIDI认为用户想松开这个键,因为9x已经打开了通道,所以我们直接写入一个带00力度的同一音符就可以决定这个音符的时值了。根据前面的分析,这个时间差应该是3C,所以我们在写入3C后写上音符45和它的力度00,即“3C 45 00”。统计好字节数并向这一轨的头信息中更新,然后保存到磁盘,用Cakewalk打开并进入事件列表窗口便可以验证了。

    在这个基础上,我们再尝试在A的后面增加一个四分音符中音#G。因为96已经打开了通道,我们没有必要每次都使用9x,只要输入事件信息即可。对于中音#G,它的十六进制是44,相对刚才输入00力度的A来说时间差为00,因此可以表示成“00 44 64”,这里我们已经假设力度为100;然后是松开它,因为是四分音符,所以时间差是78H,别忘记力度是00,它的字节应表示成“78 44 00”,做好后面的工作,然后验证看对不对。

    我们再做个稍微复杂一点的实验:在原来的基础上,在同一轨的第一拍加上一个附点四分中音D。这里就不能再使用追加的方法了,因为前面的事件已经过了3个八分音符的时间,无论再加上什么,都只会发生在后面,所以我们要在前面插入一些字节。

    9x已经打开了通道,我们直接在9x按下的音符后加上一个音符事件“00 3E 64”,这里的00显然是个时间差,3E是中音D,64是力度,也就是说,在按下中音A的同时按下了中音D。我们又按下一个键了,要在什么时候,在哪里松开才能保证输入的是个附点八分音符呢?首先,它的时值是3个八分音符,即180,这里还有一点要注意,180是个大于128的数,它的动态字节就应该表示成“81 34”,在哪里输入才好呢?如果你觉得在按下D后输入,或者在任何什么地方输入这个时间差,然后再写上“3E 00”可以表示松开的话就完全误解了时间差的概念。其实,我们只要简单地在松开#G的时候松开D就可以了,所以应该在末尾补上“00 3E 00”。统计好字节数后到Cakewalk中去验证验证吧。这里附有我们目前写下的Midi文件样本

    到目前为此,我们应该可以输入任何形式的音符了,不过MIDI除了音符以外,还可以包括各种控制器和系统码,它们的地位不亚于音符,我们现在马上学习如何使用控制器。

    控制器比音符要简单多了,我们尝试在#G前加入相位控制(Pan),它的十进制代码是10,十六进制是0A,我们将参数设置成111,即十六进制的6F。首先查得控制器是Bx,这里的x和上面一样,也是6。接下来写入控制器号0A,然后是参数6F,别忘了前面的时间差是00。所以这段字节是“00 B6 0A 6F”,它应放在松开#G的事件之前,与按下#G同时。不过,一旦使用了非音符,而后面还有音符事件时,则必须重新通知打开音符,这说起来复杂,做起来还是比较容易的,我们只要稍微改写下一个音符事件即可:原本是“时间差+音符+力度”,我们加入一个打开音符的标志,成为“时间差+9x+音符+力度”即可。校验过头信息后,去Cakewalk中进行更进一步的检验便知它的可行。

    其实,时间差为00的控制事件如果出现的时间也是00,则在Cakewalk中会尽可能地把它们放在轨道信息中,而不在事件列表中重复。我们可以利用这一点给音轨设置初始乐器和音量,这就作为一个练习,在此就不再说明了。

    至于其他的诸如触后键等与控制器类似的格式在此就不多说了。在这里有必要提醒的是滑音。滑音的乐理范围是-8192~8191,但是在使用时参数是个正数,比如要设置成0,则应该是0-(-8192)=8192,它才是参数。8192的7位双字节表示成“8192 mod 128=00H;8192 div 128=40H”。如果时间差是00,则应表示成“00 E6 00 40”

    最后我们看看系统码。系统码的构成本来是“F0 厂家ID 设备号码 格式代码 传送命令 具体参数 F7”,而在文件中,则不以开头的“F0”为系统码,而字节数也仅记录剩余的系统码,比如XG的复位码是“F0 43 10 4C 00 00 7E 00 F7”,则在文件中应写成“00 F0 08 43 10 4C 00 00 7E 00 F7”,其中第一个00是时间差,F0是系统码标志,08是后面的字节数。有一点要注意的是,几个系统码不可以写在一起,比如“00 F0 0D 43 10 4C 00 00 7E 00 F7 F0 AA BB CC F7”或“00 F0 0C 43 10 4C 00 00 7E 00 F7 AA BB CC F7”都是不好的写法。如果存在以上系统码集,可以分成两个事件:“00 F0 08 43 10 4C 00 00 7E 00 F7 00 F0 04 AA BB CC F7

    当然系统码可以写在任何音轨,不过一般我们会考虑把歌曲播放前发送的系统码写在全局音轨中,并把时间差设成00。

    作为一个参考,这里再附上一个MIDI样本

    虽然我们只讨论了同步多音轨的格式,其实对于其他两种,比如较常见的单音轨格式,所有的事件只写在一个音轨中,即只要存在一个“MTrk”就足够了。而相对地,用于记录音轨数的两个字节也永远为“00 01”,连续事件如果出现的通道不同,也必须重新指定通道(8x~Ex)。在此不详细讨论了。

    • 音符十六进制的计算
    • 关于乐器选择
    • RPN和NRPN

    在MIDI中,中央C是C5,最低音是C0,最高音是G5,要计算任何一个音符对应的十六进制,可以使用这个公式:

    假设音符是NO,表示第O八度的音名N,比如G2中,N为G,O为2,则它的十进制为O*12+N,N的值为了简便起见,用下表给出:

    这样G2的十进制值为2*12+7=31,十六进制为1F。

    若知道音符的十六进制,也可以很容易求出音符,比如64(16)=100(10)

    而100 div 12=8,100 mod 12=4,对应音符为E8。写成公式就是:

    N=B mod 12;O=B div 12;(设B为表示音符的字节的十进制数)

    乐器是MIDI中比较重要的因素,要选择所有的乐器不仅仅只是使用Cx号标志就能完成的,还必须结合BankSelect(乐队选择),而BankSelect其实是由0号控制器和32号控制器完成的,它们的十六进制代码分别是00和20.比如要选择出XG标准中的Slow Violin,它在第08H个乐队中的第28H号乐器中,所以它的完整代码应为“00 B0 00 00 00 20 08 00 C0 28”。我们来分析它的构成:这里我们假设时间差为00,所有信息都发给通道00,所以第一个00是时间差,B0是打开控制器的标志,并指定发送到通道00,接下来的00 00,是由控制器号00和控制器参数00构成的,它事实上是表示0号控制器的参数为0,即BankSelect-MSB的参数为0,然后是下一个事件,它是“00 20 08”,即时间差是00,使用20H号控制器,参数为08H,即BankSelect-LSB的参数是08H,这样就指定了Bank(乐队)。再下来就是“00 C0 28”,就是所谓的Patch Change事件了,它的时间差为00,参数是28H。这样就完成了标准的乐器选择。

    事实上,它是由三个事件共同完成的,如果某次选择乐器和上次的乐器有共同的参数,可以不必重复使用相关的操作。

    在本例中,您可能发现了一点,当连续使用同类操作时可以不必每次指定操作种类,比如这里的连续再次使用控制器,所以第二个控制器并没有使用B0作为标志,而是直接使用控制器号码和它的参数。这一点和音符是一样的。其实,如果连续使用Patch Change事件(我是说如果),则也可不必每次都写Cx,打开了一次就可以了;不过就Patch Change事件而言,连续地更换乐器的结果是仅最后一个有效而已。

    在前面的文档中并没有提及RPN和NRPN,其实它们是由四个连续的控制器来实现的。我们假设要使用RPN事件的Coarse Turning,它的参数假设是4096,则它的字节是“00 B0 65 00 00 64 02 00 06 20 00 26 00”,我们来分析这段字节:首先我们先看看RPN是由哪四个控制器组成的——首先设置RPN-MSB和RPN-LSB,分别对应的控制器是65H和64H,Coarse Turning的RPN码是2,所以MSB为0,LSB为2;然后是设置Data Entry MSB和Data Entry LSB,对应的控制器是06H和26H,而4096 div 128=32,4096 mod 128=0,对应的十六进制数分别是20H和00H。因此就构成了上面的字节。而NRPN和RPN原理是一样的,只不过不用RPN-MSB和RPN-LSB,而改用NRPN-MSB和NRPN-LSB而已,它们对应的十六进制数分别为63H和62H。
     

    展开全文
  • MidiFighterTwister-Bitwig-脚本 DJ Tech Tools Midi Fighter Twister的Bitwig脚本有关文档,请参见用户手册
  • 请参阅随附的手册页以及示例配置文件。 安装 编译此应用程序需要JACK,liblo,gnu-make和c编译器。 git clone git://github.com/x42/jackmidi2osc.git cd jackmidi2osc make # optionally install sudo make ...
  • openstack 安装手册

    千次阅读 2015-12-27 23:10:13
    #Base yum install -y http://dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-5.noarch.rpm yum install -y centos-release-openstack-liberty yum install -y python-openstackclient yum install -
    #Base
    yum install -y http://dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-5.noarch.rpm
    yum install -y centos-release-openstack-liberty
    yum install -y python-openstackclient
    yum install -y mariadb mariadb-server MySQL-python
    yum install -y rabbitmq-server
    yum install -y openstack-keystone httpd mod_wsgi memcached python-memcached
    yum install -y openstack-glance python-glance python-glanceclient
    yum install -y openstack-nova-api openstack-nova-cert openstack-nova-conductor openstack-nova-console \
    openstack-nova-novncproxy openstack-nova-scheduler python-novaclient
    yum install -y openstack-neutron openstack-neutron-ml2 openstack-neutron-linuxbridge python-neutronclient ebtables ipset
    yum install -y openstack-dashboard
    yum -y install vim  tree unzip lrzsz
    =====================linux-node2.oldboyedu.com安装
    yum install -y http://dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-5.noarch.rpm
    yum install -y centos-release-openstack-liberty
    yum install -y python-openstackclient
    yum install -y openstack-nova-compute sysfsutils 
    yum install -y openstack-neutron openstack-neutron-linuxbridge ebtables ipset
    yum -y install vim  tree unzip lrzsz




    [root@linux-node1 ~]# vi /etc/hosts
    192.168.56.11 linux-node1 linux-node1.oldboyedu.com
    192.168.56.12 linux-node2 linux-node2.oldboyedu.com


    关闭selinux
    setenforce 0  
    sed -i '/SELINUX/s/enforcing/disabled/' /etc/selinux/config 


    关闭防火墙
    systemctl stop firewalld.service
    systemctl disable firewalld.service


    时间同步
    [root@linux-node1 ~]# yum install chrony
    [root@linux-node1 ~]# vi /etc/chrony.conf
    打开注释
    allow 192.168/16


    [root@linux-node1 ~]# systemctl enable chronyd.service
    [root@linux-node1 ~]# systemctl start chronyd.service


    时区设置
    [root@linux-node1 ~]# timedatectl set-timezone Asia/Shanghai 
    [root@linux-node1 ~]# date
    Sun Dec 27 14:12:12 CST 2015
    ##################################################################################################
    安装及修改数据库配置文件
    [root@linux-node1 ~]# cp /usr/share/mysql/my-medium.cnf /etc/my.cnf
    cp: overwrite ‘/etc/my.cnf’? y
    [root@linux-node1 ~]# vim /etc/my.cnf
    [mysqld]
    default-storage-engine = innodb
    innodb_file_per_table
    collation-server = utf8_general_ci
    init-connect = 'SET NAMES utf8'
    character-set-server = utf8
    设置开机mysql自动启动
    [root@linux-node1 ~]# systemctl enable mariadb.service
    ln -s '/usr/lib/systemd/system/mariadb.service' '/etc/systemd/system/multi-user.target.wants/mariadb.service'
    [root@linux-node1 ~]# systemctl start mariadb.service
    Mysql设置密码
    [root@linux-node1 ~]# mysql_secure_installation 
    /usr/bin/mysql_secure_installation: line 379: find_mysql_client: command not found


    NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB
          SERVERS IN PRODUCTION USE!  PLEASE READ EACH STEP CAREFULLY!


    In order to log into MariaDB to secure it, we'll need the current
    password for the root user.  If you've just installed MariaDB, and
    you haven't set the root password yet, the password will be blank,
    so you should just press enter here.


    Enter current password for root (enter for none): --回车键
    OK, successfully used password, moving on...


    Setting the root password ensures that nobody can log into the MariaDB
    root user without the proper authorisation.


    Set root password? [Y/n] y
    New password: 
    Re-enter new password: 
    Password updated successfully!
    Reloading privilege tables..
     ... Success!




    By default, a MariaDB installation has an anonymous user, allowing anyone
    to log into MariaDB without having to have a user account created for
    them.  This is intended only for testing, and to make the installation
    go a bit smoother.  You should remove them before moving into a
    production environment.


    Remove anonymous users? [Y/n] y
     ... Success!


    Normally, root should only be allowed to connect from 'localhost'.  This
    ensures that someone cannot guess at the root password from the network.


    Disallow root login remotely? [Y/n] y
     ... Success!


    By default, MariaDB comes with a database named 'test' that anyone can
    access.  This is also intended only for testing, and should be removed
    before moving into a production environment.


    Remove test database and access to it? [Y/n] y
     - Dropping test database...
     ... Success!
     - Removing privileges on test database...
     ... Success!


    Reloading the privilege tables will ensure that all changes made so far
    will take effect immediately.


    Reload privilege tables now? [Y/n] y
     ... Success!


    Cleaning up...


    All done!  If you've completed all of the above steps, your MariaDB
    installation should now be secure.


    Thanks for using MariaDB!


    创建数据库
    #keystone数据库
    mysql -u root -p -e "CREATE DATABASE keystone;"
    mysql -u root -p -e "GRANT ALL PRIVILEGES ON keystone.* TO 'keystone'@'localhost' IDENTIFIED BY 'keystone';"
    mysql -u root -p -e "GRANT ALL PRIVILEGES ON keystone.* TO 'keystone'@'%' IDENTIFIED BY 'keystone';"
    #Glance数据库
    mysql -u root -p -e "CREATE DATABASE glance;"
    mysql -u root -p -e "GRANT ALL PRIVILEGES ON glance.* TO 'glance'@'localhost' IDENTIFIED BY 'glance';"
    mysql -u root -p -e "GRANT ALL PRIVILEGES ON glance.* TO 'glance'@'%' IDENTIFIED BY 'glance';"
    #Nova数据库
    mysql -u root -p -e "CREATE DATABASE nova;"
    mysql -u root -p -e "GRANT ALL PRIVILEGES ON nova.* TO 'nova'@'localhost' IDENTIFIED BY 'nova';"
    mysql -u root -p -e "GRANT ALL PRIVILEGES ON nova.* TO 'nova'@'%' IDENTIFIED BY 'nova';"
    #Neutron 数据库
    mysql -u root -p -e "CREATE DATABASE neutron;"
    mysql -u root -p -e "GRANT ALL PRIVILEGES ON neutron.* TO 'neutron'@'localhost' IDENTIFIED BY 'neutron';"
    mysql -u root -p -e "GRANT ALL PRIVILEGES ON neutron.* TO 'neutron'@'%' IDENTIFIED BY 'neutron';"
    #Cinder数据库
    mysql -u root -p -e "CREATE DATABASE cinder;"
    mysql -u root -p -e "GRANT ALL PRIVILEGES ON cinder.* TO 'cinder'@'localhost' IDENTIFIED BY 'cinder';"
    mysql -u root -p -e "GRANT ALL PRIVILEGES ON cinder.* TO 'cinder'@'%' IDENTIFIED BY 'cinder';"


    [root@linux-node1 ~]# mysql -u root -p
    Enter password: 
    Welcome to the MariaDB monitor.  Commands end with ; or \g.
    Your MariaDB connection id is 25
    Server version: 5.5.44-MariaDB-log MariaDB Server


    Copyright (c) 2000, 2015, Oracle, MariaDB Corporation Ab and others.


    Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.


    MariaDB [(none)]> show databases;
    +--------------------+
    | Database           |
    +--------------------+
    | information_schema |
    | cinder             |
    | glance             |
    | keystone           |
    | mysql              |
    | neutron            |
    | nova               |
    | performance_schema |
    +--------------------+
    8 rows in set (0.00 sec)
    ################################################################################################
    rabbitmq消息服务器
    rabbitmq服务开机自动启动
    [root@linux-node1 ~]# systemctl enable rabbitmq-server.service
    ln -s '/usr/lib/systemd/system/rabbitmq-server.service' '/etc/systemd/system/multi-user.target.wants/rabbitmq-server.service'
    [root@linux-node1 ~]# systemctl start rabbitmq-server.service
    查看端口:rabbitmq的端口是5672
    [root@linux-node1 ~]# netstat -lntup
    Active Internet connections (only servers)
    Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
    tcp        0      0 0.0.0.0:25672           0.0.0.0:*               LISTEN      4184/beam.smp       
    tcp        0      0 0.0.0.0:3306            0.0.0.0:*               LISTEN      4041/mysqld         
    tcp        0      0 0.0.0.0:4369            0.0.0.0:*               LISTEN      4199/epmd           
    tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1111/sshd           
    tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      2218/master         
    tcp6       0      0 :::5672                 :::*                    LISTEN      4184/beam.smp       
    tcp6       0      0 :::22                   :::*                    LISTEN      1111/sshd           
    tcp6       0      0 ::1:25                  :::*                    LISTEN      2218/master         
    udp        0      0 127.0.0.1:323           0.0.0.0:*                           868/chronyd         
    udp6       0      0 ::1:323                 :::*                                868/chronyd 
    创建openstack的用户名和密码
    [root@linux-node1 ~]#  rabbitmqctl add_user openstack openstack
    Creating user "openstack" ...
    ...done.
    用户授权
    [root@linux-node1 ~]# rabbitmqctl set_permissions openstack ".*" ".*" ".*"
    Setting permissions for user "openstack" in vhost "/" ...
    ...done.
    列出rabbitmq的插件
    [root@linux-node1 ~]# rabbitmq-plugins list
    [ ] amqp_client                       3.3.5
    [ ] cowboy                            0.5.0-rmq3.3.5-git4b93c2d
    [ ] eldap                             3.3.5-gite309de4
    [ ] mochiweb                          2.7.0-rmq3.3.5-git680dba8
    [ ] rabbitmq_amqp1_0                  3.3.5
    [ ] rabbitmq_auth_backend_ldap        3.3.5
    [ ] rabbitmq_auth_mechanism_ssl       3.3.5
    [ ] rabbitmq_consistent_hash_exchange 3.3.5
    [ ] rabbitmq_federation               3.3.5
    [ ] rabbitmq_federation_management    3.3.5
    [ ] rabbitmq_management               3.3.5
    [ ] rabbitmq_management_agent         3.3.5
    [ ] rabbitmq_management_visualiser    3.3.5
    [ ] rabbitmq_mqtt                     3.3.5
    [ ] rabbitmq_shovel                   3.3.5
    [ ] rabbitmq_shovel_management        3.3.5
    [ ] rabbitmq_stomp                    3.3.5
    [ ] rabbitmq_test                     3.3.5
    [ ] rabbitmq_tracing                  3.3.5
    [ ] rabbitmq_web_dispatch             3.3.5
    [ ] rabbitmq_web_stomp                3.3.5
    [ ] rabbitmq_web_stomp_examples       3.3.5
    [ ] sockjs                            0.3.4-rmq3.3.5-git3132eb9
    [ ] webmachine                        1.10.3-rmq3.3.5-gite9359c7
    rabbitmq管理插件启动
    [root@linux-node1 ~]# rabbitmq-plugins enable rabbitmq_management 
    The following plugins have been enabled:
      mochiweb
      webmachine
      rabbitmq_web_dispatch
      amqp_client
      rabbitmq_management_agent
      rabbitmq_management
    Plugin configuration has changed. Restart RabbitMQ for changes to take effect.
    重新启动rabbitmq
    [root@linux-node1 ~]# systemctl restart rabbitmq-server.service
    再次查看监听的端口:web管理端口:15672
    [root@linux-node1 ~]# netstat -lntup
    Active Internet connections (only servers)
    Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
    tcp        0      0 0.0.0.0:25672           0.0.0.0:*               LISTEN      4581/beam.smp       
    tcp        0      0 0.0.0.0:3306            0.0.0.0:*               LISTEN      4041/mysqld         
    tcp        0      0 0.0.0.0:4369            0.0.0.0:*               LISTEN      4597/epmd           
    tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1111/sshd           
    tcp        0      0 0.0.0.0:15672           0.0.0.0:*               LISTEN      4581/beam.smp       
    tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      2218/master         
    tcp6       0      0 :::5672                 :::*                    LISTEN      4581/beam.smp       
    tcp6       0      0 :::22                   :::*                    LISTEN      1111/sshd           
    tcp6       0      0 ::1:25                  :::*                    LISTEN      2218/master         
    udp        0      0 127.0.0.1:323           0.0.0.0:*                           868/chronyd         
    udp6       0      0 ::1:323                 :::*                                868/chronyd  
    打开http://192.168.56.11:15672/  用户名 guest      密码 guest 
    登录进去之后:
    Admin------->复制administrator------->点击openstack------>Update this user-------->
    Tags:粘帖administrator--------->密码都设置为openstack-------->logout
    然后在登陆:用户名 openstack  密码  openstack
    ##############################################################################################################
    Keystone 验证服务
    [root@linux-node1 ~]# yum -y install lrzsz unzip


    [root@linux-node1 ~]# openssl rand -hex 10
    bd56bcaa58d488a45188
    [root@linux-node1 ~]# grep -n '^[a-z]'  /etc/keystone/keystone.conf
    12:admin_token = bd56bcaa58d488a45188
    107:verbose = true
    495:connection = mysql://keystone:keystone@192.168.56.11/keystone
    1305:servers = 192.168.56.11:11211
    1341:driver = sql
    1903:provider = uuid
    1908:driver = memcache
    同步数据库:注意权限,所以要用su -s 切换到keystone用户下执行:
    [root@linux-node1 ~]# su -s /bin/sh -c "keystone-manage db_sync" keystone
    No handlers could be found for logger "oslo_config.cfg"
    验证数据是否创建成功
    [root@linux-node1 ~]# mysql -ukeystone -pkeystone
    Welcome to the MariaDB monitor.  Commands end with ; or \g.
    Your MariaDB connection id is 27
    Server version: 5.5.44-MariaDB-log MariaDB Server


    Copyright (c) 2000, 2015, Oracle, MariaDB Corporation Ab and others.


    Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.


    MariaDB [(none)]> use keystone
    Database changed
    MariaDB [keystone]> show tables
        -> ;
    +------------------------+
    | Tables_in_keystone     |
    +------------------------+
    | access_token           |
    | assignment             |
    | config_register        |
    | consumer               |
    | credential             |
    | domain                 |
    | endpoint               |
    | endpoint_group         |
    | federation_protocol    |
    | group                  |
    | id_mapping             |
    | identity_provider      |
    | idp_remote_ids         |
    | mapping                |
    | migrate_version        |
    | policy                 |
    | policy_association     |
    | project                |
    | project_endpoint       |
    | project_endpoint_group |
    | region                 |
    | request_token          |
    | revocation_event       |
    | role                   |
    | sensitive_config       |
    | service                |
    | service_provider       |
    | token                  |
    | trust                  |
    | trust_role             |
    | user                   |
    | user_group_membership  |
    | whitelisted_config     |
    +------------------------+
    33 rows in set (0.00 sec)
    启动memcache服务
    [root@linux-node1 ~]# systemctl start memcached.service
    新建keystone配置文件,并用apache来代理它:5000  正常的api来访问  35357  管理访问的端口
    [root@linux-node1 ~]# vim /etc/httpd/conf.d/wsgi-keystone.conf
    Listen 5000
    Listen 35357


    <VirtualHost *:5000>
        WSGIDaemonProcess keystone-public processes=5 threads=1 user=keystone group=keystone display-name=%{GROUP}
        WSGIProcessGroup keystone-public
        WSGIScriptAlias / /usr/bin/keystone-wsgi-public
        WSGIApplicationGroup %{GLOBAL}
        WSGIPassAuthorization On
        <IfVersion >= 2.4>
          ErrorLogFormat "%{cu}t %M"
        </IfVersion>
        ErrorLog /var/log/httpd/keystone-error.log
        CustomLog /var/log/httpd/keystone-access.log combined


        <Directory /usr/bin>
            <IfVersion >= 2.4>
                Require all granted
            </IfVersion>
            <IfVersion < 2.4>
                Order allow,deny
                Allow from all
            </IfVersion>
        </Directory>
    </VirtualHost>


    <VirtualHost *:35357>
        WSGIDaemonProcess keystone-admin processes=5 threads=1 user=keystone group=keystone display-name=%{GROUP}
        WSGIProcessGroup keystone-admin
        WSGIScriptAlias / /usr/bin/keystone-wsgi-admin
        WSGIApplicationGroup %{GLOBAL}
        WSGIPassAuthorization On
        <IfVersion >= 2.4>
          ErrorLogFormat "%{cu}t %M"
        </IfVersion>
        ErrorLog /var/log/httpd/keystone-error.log
        CustomLog /var/log/httpd/keystone-access.log combined


        <Directory /usr/bin>
            <IfVersion >= 2.4>
                Require all granted
            </IfVersion>
            <IfVersion < 2.4>
                Order allow,deny
                Allow from all
            </IfVersion>
        </Directory>
    </VirtualHost>
    必须要配置httpd的ServerName,否则keystone服务不能起来
    [root@linux-node1 ~]# grep -n '^ServerName' /etc/httpd/conf/httpd.conf      
    95:ServerName 192.168.56.11:80
    启动memcache与httpd服务
    [root@linux-node1 ~]# systemctl enable memcached
    ln -s '/usr/lib/systemd/system/memcached.service' '/etc/systemd/system/multi-user.target.wants/memcached.service'
    [root@linux-node1 ~]#  systemctl enable httpd
    ln -s '/usr/lib/systemd/system/httpd.service' '/etc/systemd/system/multi-user.target.wants/httpd.service'
    [root@linux-node1 ~]# systemctl start httpd
    查看端口
    [root@linux-node1 ~]# netstat -lntup|grep httpd
    tcp6       0      0 :::5000                 :::*                    LISTEN      5361/httpd          
    tcp6       0      0 :::80                   :::*                    LISTEN      5361/httpd          
    tcp6       0      0 :::35357                :::*                    LISTEN      5361/httpd   
    创建验证用户及地址版本信息
    [root@linux-node1 ~]# grep -n '^admin_token' /etc/keystone/keystone.conf
    12:admin_token = bd56bcaa58d488a45188
    [root@linux-node1 ~]# export OS_TOKEN=bd56bcaa58d488a45188
    [root@linux-node1 ~]# export OS_URL=http://192.168.56.11:35357/v3
    [root@linux-node1 ~]# export OS_IDENTITY_API_VERSION=3
    [root@linux-node1 ~]# env
    XDG_SESSION_ID=5
    HOSTNAME=linux-node1
    TERM=xterm
    SHELL=/bin/bash
    HISTSIZE=1000
    SSH_CLIENT=192.168.56.1 53607 22
    SSH_TTY=/dev/pts/0
    USER=root
    LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:
    MAIL=/var/spool/mail/root
    PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
    OS_IDENTITY_API_VERSION=3
    PWD=/root
    LANG=en_US.UTF-8
    HISTCONTROL=ignoredups
    OS_TOKEN=bd56bcaa58d488a45188
    SHLVL=1
    HOME=/root
    LOGNAME=root
    SSH_CONNECTION=192.168.56.1 53607 192.168.56.11 22
    LESSOPEN=||/usr/bin/lesspipe.sh %s
    OS_URL=http://192.168.56.11:35357/v3
    XDG_RUNTIME_DIR=/run/user/0
    _=/usr/bin/env
    创建租户用户
    [root@linux-node1 ~]# openstack project create --domain default   --description "Admin Project" admin
    +-------------+----------------------------------+
    | Field       | Value                            |
    +-------------+----------------------------------+
    | description | Admin Project                    |
    | domain_id   | default                          |
    | enabled     | True                             |
    | id          | 53ae41ed2d2e4240980ba4e7dfadf4de |
    | is_domain   | False                            |
    | name        | admin                            |
    | parent_id   | None                             |
    +-------------+----------------------------------+
    创建admin的用户
    [root@linux-node1 ~]# openstack user create --domain default --password-prompt admin
    User Password:
    Repeat User Password:
    +-----------+----------------------------------+
    | Field     | Value                            |
    +-----------+----------------------------------+
    | domain_id | default                          |
    | enabled   | True                             |
    | id        | 8a77d890d93b4656a3b7893cb90eb733 |
    | name      | admin                            |
    +-----------+----------------------------------+
    创建admin的角色
    [root@linux-node1 ~]# openstack role create admin
    +-------+----------------------------------+
    | Field | Value                            |
    +-------+----------------------------------+
    | id    | 6e626607a20c47bda440c5c94dc3bcde |
    | name  | admin                            |
    +-------+----------------------------------+
    把admin用户加入到admin项目,并赋予admin的角色
    [root@linux-node1 ~]# openstack role add --project admin --user admin admin
    创建普通用户密码及角色
    [root@linux-node1 ~]# openstack project create --domain default --description "Demo Project" demo
    +-------------+----------------------------------+
    | Field       | Value                            |
    +-------------+----------------------------------+
    | description | Demo Project                     |
    | domain_id   | default                          |
    | enabled     | True                             |
    | id          | 7d196866c81342f49ef1b083eb45e828 |
    | is_domain   | False                            |
    | name        | demo                             |
    | parent_id   | None                             |
    +-------------+----------------------------------+


    [root@linux-node1 ~]# openstack user create --domain default --password=demo demo
    +-----------+----------------------------------+
    | Field     | Value                            |
    +-----------+----------------------------------+
    | domain_id | default                          |
    | enabled   | True                             |
    | id        | 7c241c29598b4b30a6e41e9168308b93 |
    | name      | demo                             |
    +-----------+----------------------------------+
    [root@linux-node1 ~]# openstack role create user
    +-------+----------------------------------+
    | Field | Value                            |
    +-------+----------------------------------+
    | id    | bafdaf22db03409bbde3b9d360b5d1e4 |
    | name  | user                             |
    +-------+----------------------------------+
    [root@linux-node1 ~]# openstack role add --project demo --user demo user
    创建一个Service的项目
    [root@linux-node1 ~]# openstack project create --domain default --description "Service Project" service
    +-------------+----------------------------------+
    | Field       | Value                            |
    +-------------+----------------------------------+
    | description | Service Project                  |
    | domain_id   | default                          |
    | enabled     | True                             |
    | id          | 7489313a1a164b879cf3618a0fdaaa0e |
    | is_domain   | False                            |
    | name        | service                          |
    | parent_id   | None                             |
    +-------------+----------------------------------+
    查看创建的用户及角色
    [root@linux-node1 ~]# openstack user list
    +----------------------------------+-------+
    | ID                               | Name  |
    +----------------------------------+-------+
    | 7c241c29598b4b30a6e41e9168308b93 | demo  |
    | 8a77d890d93b4656a3b7893cb90eb733 | admin |
    +----------------------------------+-------+
    [root@linux-node1 ~]# openstack role list
    +----------------------------------+-------+
    | ID                               | Name  |
    +----------------------------------+-------+
    | 6e626607a20c47bda440c5c94dc3bcde | admin |
    | bafdaf22db03409bbde3b9d360b5d1e4 | user  |
    +----------------------------------+-------+
    [root@linux-node1 ~]# openstack project list
    +----------------------------------+---------+
    | ID                               | Name    |
    +----------------------------------+---------+
    | 53ae41ed2d2e4240980ba4e7dfadf4de | admin   |
    | 7489313a1a164b879cf3618a0fdaaa0e | service |
    | 7d196866c81342f49ef1b083eb45e828 | demo    |
    +----------------------------------+---------+
    keystone本身也需要注册
    [root@linux-node1 ~]# openstack service create --name keystone --description "OpenStack Identity" identity
    +-------------+----------------------------------+
    | Field       | Value                            |
    +-------------+----------------------------------+
    | description | OpenStack Identity               |
    | enabled     | True                             |
    | id          | 88eeee6ec1434b6dbee4b011abcc1957 |
    | name        | keystone                         |
    | type        | identity                         |
    +-------------+----------------------------------+
    公共的api接口
    [root@linux-node1 ~]# openstack endpoint create --region RegionOne identity public http://192.168.56.11:5000/v2.0
    +--------------+----------------------------------+
    | Field        | Value                            |
    +--------------+----------------------------------+
    | enabled      | True                             |
    | id           | 2c211a7252624a31a9102750487b7a7b |
    | interface    | public                           |
    | region       | RegionOne                        |
    | region_id    | RegionOne                        |
    | service_id   | 88eeee6ec1434b6dbee4b011abcc1957 |
    | service_name | keystone                         |
    | service_type | identity                         |
    | url          | http://192.168.56.11:5000/v2.0   |
    +--------------+----------------------------------+
    私有的api接口
    [root@linux-node1 ~]# openstack endpoint create --region RegionOne identity internal http://192.168.56.11:5000/v2.0
    +--------------+----------------------------------+
    | Field        | Value                            |
    +--------------+----------------------------------+
    | enabled      | True                             |
    | id           | 4d3a182881d44459a927f36df286e2bb |
    | interface    | internal                         |
    | region       | RegionOne                        |
    | region_id    | RegionOne                        |
    | service_id   | 88eeee6ec1434b6dbee4b011abcc1957 |
    | service_name | keystone                         |
    | service_type | identity                         |
    | url          | http://192.168.56.11:5000/v2.0   |
    +--------------+----------------------------------+
    管理的api接口
    [root@linux-node1 ~]# openstack endpoint create --region RegionOne identity admin http://192.168.56.11:35357/v2.0
    +--------------+----------------------------------+
    | Field        | Value                            |
    +--------------+----------------------------------+
    | enabled      | True                             |
    | id           | 4fd0af813acc48738bc6003ebe9da49e |
    | interface    | admin                            |
    | region       | RegionOne                        |
    | region_id    | RegionOne                        |
    | service_id   | 88eeee6ec1434b6dbee4b011abcc1957 |
    | service_name | keystone                         |
    | service_type | identity                         |
    | url          | http://192.168.56.11:35357/v2.0  |
    +--------------+----------------------------------+
    查看api接口
    [root@linux-node1 ~]# openstack endpoint list
    +----------------------------------+-----------+--------------+--------------+---------+-----------+---------------------------------+
    | ID                               | Region    | Service Name | Service Type | Enabled | Interface | URL                             |
    +----------------------------------+-----------+--------------+--------------+---------+-----------+---------------------------------+
    | 2c211a7252624a31a9102750487b7a7b | RegionOne | keystone     | identity     | True    | public    | http://192.168.56.11:5000/v2.0  |
    | 4d3a182881d44459a927f36df286e2bb | RegionOne | keystone     | identity     | True    | internal  | http://192.168.56.11:5000/v2.0  |
    | 4fd0af813acc48738bc6003ebe9da49e | RegionOne | keystone     | identity     | True    | admin     | http://192.168.56.11:35357/v2.0 |
    +----------------------------------+-----------+--------------+--------------+---------+-----------+---------------------------------+
    使用用户名密码的方式登录:必须要先取消环境变量
    [root@linux-node1 ~]# unset OS_TOKEN
    [root@linux-node1 ~]# unset OS_URL
    [root@linux-node1 ~]# openstack --os-auth-url http://192.168.56.11:35357/v3 --os-project-domain-id default --os-user-domain-id default --os-project-name admin --os-username admin --os-auth-type password token issue
    Password: admin
    +------------+----------------------------------+
    | Field      | Value                            |
    +------------+----------------------------------+
    | expires    | 2015-12-27T08:51:56.977380Z      |
    | id         | 4d095f0f361247ecb1fd3719f70a4cea |
    | project_id | 53ae41ed2d2e4240980ba4e7dfadf4de |
    | user_id    | 8a77d890d93b4656a3b7893cb90eb733 |
    +------------+----------------------------------+
    说明keystone成功了。


    便快捷的使用keystone,我们需要设置两个环境变量:
    [root@linux-node1 ~]# vim admin-openrc.sh
    export OS_PROJECT_DOMAIN_ID=default
    export OS_USER_DOMAIN_ID=default
    export OS_PROJECT_NAME=admin
    export OS_TENANT_NAME=admin
    export OS_USERNAME=admin
    export OS_PASSWORD=admin
    export OS_AUTH_URL=http://192.168.56.11:35357/v3
    export OS_IDENTITY_API_VERSION=3
    linux-node1 ~]# vim demo-openrc.sh
    export OS_PROJECT_DOMAIN_ID=default
    export OS_USER_DOMAIN_ID=default
    export OS_PROJECT_NAME=demo
    export OS_TENANT_NAME=demo
    export OS_USERNAME=demo
    export OS_PASSWORD=demo
    export OS_AUTH_URL=http://192.168.56.11:5000/v3
    export OS_IDENTITY_API_VERSION=3
    添加执行权限
    [root@linux-node1 ~]# chmod +x admin-openrc.sh demo-openrc.sh 
    [root@linux-node1 ~]# openstack token issue
    +------------+----------------------------------+
    | Field      | Value                            |
    +------------+----------------------------------+
    | expires    | 2015-12-27T09:04:20.860096Z      |
    | id         | 80e87eb4b69642be8137ffec8018858d |
    | project_id | 53ae41ed2d2e4240980ba4e7dfadf4de |
    | user_id    | 8a77d890d93b4656a3b7893cb90eb733 |
    +------------+----------------------------------+
    ##############################################################################################################
    Glance部署
    修改配置文件添加数据库连接glance-api.conf与glance-registry.conf
    [root@linux-node1 ~]# vi +538 /etc/glance/glance-api.conf
    [root@linux-node1 ~]# grep -n '^connection' /etc/glance/glance-api.conf
    538:connection=mysql://glance:glance@192.168.56.11/glance
    [root@linux-node1 ~]# vi +363 /etc/glance/glance-registry.conf 
    [root@linux-node1 ~]# grep -n '^connection' /etc/glance/glance-registry.conf 
    363:connection=mysql://glance:glance@192.168.56.11/glance
    同步数据库
    [root@linux-node1 ~]# su -s /bin/sh -c "glance-manage db_sync" glance
    查看数据库同步是否成功
    [root@linux-node1 ~]# mysql -uglance -pglance -h 192.168.56.11
    Welcome to the MariaDB monitor.  Commands end with ; or \g.
    Your MariaDB connection id is 34
    Server version: 5.5.44-MariaDB-log MariaDB Server


    Copyright (c) 2000, 2015, Oracle, MariaDB Corporation Ab and others.


    Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.


    MariaDB [(none)]> use glance
    Database changed
    MariaDB [glance]> show tables;
    +----------------------------------+
    | Tables_in_glance                 |
    +----------------------------------+
    | artifact_blob_locations          |
    | artifact_blobs                   |
    | artifact_dependencies            |
    | artifact_properties              |
    | artifact_tags                    |
    | artifacts                        |
    | image_locations                  |
    | image_members                    |
    | image_properties                 |
    | image_tags                       |
    | images                           |
    | metadef_namespace_resource_types |
    | metadef_namespaces               |
    | metadef_objects                  |
    | metadef_properties               |
    | metadef_resource_types           |
    | metadef_tags                     |
    | migrate_version                  |
    | task_info                        |
    | tasks                            |
    +----------------------------------+
    20 rows in set (0.00 sec)
    创建glance用户
    [root@linux-node1 ~]# source admin-openrc.sh 
    [root@linux-node1 ~]# openstack user create --domain default --password=glance glance
    +-----------+----------------------------------+
    | Field     | Value                            |
    +-----------+----------------------------------+
    | domain_id | default                          |
    | enabled   | True                             |
    | id        | c6a15226c2be4dd1957fb441fb9e8464 |
    | name      | glance                           |
    +-----------+----------------------------------+
    将此用户加入到项目里面并给它赋予admin的权限
    [root@linux-node1 ~]# openstack role add --project service --user glance admin
    配置keystone与glance-api.conf的链接
    [root@linux-node1 glance]# grep -n '^[a-z]' /etc/glance/glance-api.conf 
    363:verbose=True
    491:notification_driver = noop
    538:connection=mysql://glance:glance@192.168.56.11/glance
    642:default_store=file
    701:filesystem_store_datadir=/var/lib/glance/images/
    974:auth_uri = http://192.168.56.11:5000
    975:auth_url = http://192.168.56.11:35357
    976:auth_plugin = password
    977:project_domain_id = default
    978:user_domain_id = default
    979:project_name = service
    980:username = glance
    981:password = glance
    1484:flavor=keystone
    配置keystone与glance-registry.conf的链接
    [root@linux-node1 glance]# grep -n '^[a-z]' /etc/glance/glance-registry.conf 
    363:connection=mysql://glance:glance@192.168.56.11/glance
    763:auth_uri = http://192.168.56.11:5000
    764:auth_url = http://192.168.56.11:35357
    765:auth_plugin = password
    766:project_domain_id = default
    767:user_domain_id = default
    768:project_name = service
    769:username = glance
    770:password = glance
    1256:flavor=keystone
    启动glance服务并设置开机启动
    [root@linux-node1 glance]# systemctl enable openstack-glance-api
    ln -s '/usr/lib/systemd/system/openstack-glance-api.service' '/etc/systemd/system/multi-user.target.wants/openstack-glance-api.service'
    [root@linux-node1 glance]# systemctl enable openstack-glance-registry
    ln -s '/usr/lib/systemd/system/openstack-glance-registry.service' '/etc/systemd/system/multi-user.target.wants/openstack-glance-registry.service'
    [root@linux-node1 glance]# systemctl start openstack-glance-api
    [root@linux-node1 glance]# systemctl start openstack-glance-registry
    监听端口: registry:9191     api:9292
    [root@linux-node1 glance]# netstat -antup
    Active Internet connections (servers and established)
    Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
    tcp        0      0 0.0.0.0:9191            0.0.0.0:*               LISTEN      6570/python2        
    tcp        0      0 0.0.0.0:25672           0.0.0.0:*               LISTEN      4581/beam.smp       
    tcp        0      0 0.0.0.0:3306            0.0.0.0:*               LISTEN      4041/mysqld         
    tcp        0      0 0.0.0.0:11211           0.0.0.0:*               LISTEN      5245/memcached      
    tcp        0      0 0.0.0.0:9292            0.0.0.0:*               LISTEN      6555/python2        
    tcp        0      0 0.0.0.0:4369            0.0.0.0:*               LISTEN      4597/epmd           
    tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1111/sshd           
    tcp        0      0 0.0.0.0:15672           0.0.0.0:*               LISTEN      4581/beam.smp       
    tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      2218/master         
    tcp        0      0 127.0.0.1:42434         127.0.0.1:4369          ESTABLISHED 4581/beam.smp       
    tcp        0      0 192.168.56.11:60237     192.168.56.11:3306      ESTABLISHED 5369/(wsgi:keystone 
    tcp        0      0 192.168.56.11:60247     192.168.56.11:3306      ESTABLISHED 5373/(wsgi:keystone 
    tcp        0      0 192.168.56.11:3306      192.168.56.11:60247     ESTABLISHED 4041/mysqld         
    tcp        0      0 192.168.56.11:44854     192.168.56.11:11211     ESTABLISHED 5373/(wsgi:keystone 
    tcp        0      0 192.168.56.11:3306      192.168.56.11:60237     ESTABLISHED 4041/mysqld         
    tcp        0      0 192.168.56.11:11211     192.168.56.11:44854     ESTABLISHED 5245/memcached      
    tcp        0      0 192.168.56.11:3306      192.168.56.11:60244     ESTABLISHED 4041/mysqld         
    tcp        0      0 127.0.0.1:4369          127.0.0.1:42434         ESTABLISHED 4597/epmd           
    tcp        0      0 192.168.56.11:15672     192.168.56.1:62402      ESTABLISHED 4581/beam.smp       
    tcp        0      0 192.168.56.11:44859     192.168.56.11:11211     ESTABLISHED 5370/(wsgi:keystone 
    tcp        0      0 192.168.56.11:3306      192.168.56.11:60239     ESTABLISHED 4041/mysqld         
    tcp        0      0 192.168.56.11:3306      192.168.56.11:60241     ESTABLISHED 4041/mysqld         
    tcp        0     52 192.168.56.11:22        192.168.56.1:53607      ESTABLISHED 2441/sshd: root@pts 
    tcp        0      0 192.168.56.11:60239     192.168.56.11:3306      ESTABLISHED 5370/(wsgi:keystone 
    tcp        0      0 192.168.56.11:60241     192.168.56.11:3306      ESTABLISHED 5371/(wsgi:keystone 
    tcp        0      0 192.168.56.11:11211     192.168.56.11:44859     ESTABLISHED 5245/memcached      
    tcp        0      0 192.168.56.11:60244     192.168.56.11:3306      ESTABLISHED 5372/(wsgi:keystone 
    tcp6       0      0 :::5000                 :::*                    LISTEN      5361/httpd          
    tcp6       0      0 :::5672                 :::*                    LISTEN      4581/beam.smp       
    tcp6       0      0 :::11211                :::*                    LISTEN      5245/memcached      
    tcp6       0      0 :::80                   :::*                    LISTEN      5361/httpd          
    tcp6       0      0 :::22                   :::*                    LISTEN      1111/sshd           
    tcp6       0      0 ::1:25                  :::*                    LISTEN      2218/master         
    tcp6       0      0 :::35357                :::*                    LISTEN      5361/httpd          
    udp        0      0 127.0.0.1:323           0.0.0.0:*                           868/chronyd         
    udp        0      0 0.0.0.0:11211           0.0.0.0:*                           5245/memcached      
    udp6       0      0 ::1:323                 :::*                                868/chronyd         
    udp6       0      0 :::11211                :::*                                5245/memcached     


    glance服务创建
    [root@linux-node1 ~]# source admin-openrc.sh 
    [root@linux-node1 ~]# openstack service create --name glance --description "OpenStack Image service" image
    +-------------+----------------------------------+
    | Field       | Value                            |
    +-------------+----------------------------------+
    | description | OpenStack Image service          |
    | enabled     | True                             |
    | id          | 1c9b0d790cee4e3e81b0a71c16b72fd2 |
    | name        | glance                           |
    | type        | image                            |
    +-------------+----------------------------------+
    [root@linux-node1 ~]# openstack endpoint create --region RegionOne   image public http://192.168.56.11:9292
    +--------------+----------------------------------+
    | Field        | Value                            |
    +--------------+----------------------------------+
    | enabled      | True                             |
    | id           | 0273eb69de7d48a4a0829af85579a1e3 |
    | interface    | public                           |
    | region       | RegionOne                        |
    | region_id    | RegionOne                        |
    | service_id   | 1c9b0d790cee4e3e81b0a71c16b72fd2 |
    | service_name | glance                           |
    | service_type | image                            |
    | url          | http://192.168.56.11:9292        |
    +--------------+----------------------------------+
    [root@linux-node1 ~]# openstack endpoint create --region RegionOne   image internal http://192.168.56.11:9292
    +--------------+----------------------------------+
    | Field        | Value                            |
    +--------------+----------------------------------+
    | enabled      | True                             |
    | id           | a05eba9ba09a471ca5e7f328fa500e6c |
    | interface    | internal                         |
    | region       | RegionOne                        |
    | region_id    | RegionOne                        |
    | service_id   | 1c9b0d790cee4e3e81b0a71c16b72fd2 |
    | service_name | glance                           |
    | service_type | image                            |
    | url          | http://192.168.56.11:9292        |
    +--------------+----------------------------------+
    [root@linux-node1 ~]# openstack endpoint create --region RegionOne   image admin http://192.168.56.11:9292
    +--------------+----------------------------------+
    | Field        | Value                            |
    +--------------+----------------------------------+
    | enabled      | True                             |
    | id           | 2f89afebf0414db483e9067c24f249c3 |
    | interface    | admin                            |
    | region       | RegionOne                        |
    | region_id    | RegionOne                        |
    | service_id   | 1c9b0d790cee4e3e81b0a71c16b72fd2 |
    | service_name | glance                           |
    | service_type | image                            |
    | url          | http://192.168.56.11:9292        |
    +--------------+----------------------------------+
    环境变量添加OS_IMAGE_API_VERSION
    [root@linux-node1 ~]# echo "export OS_IMAGE_API_VERSION=2" \
    >   | tee -a admin-openrc.sh demo-openrc.sh
    export OS_IMAGE_API_VERSION=2
    [root@linux-node1 ~]# glance image-list
    +----+------+
    | ID | Name |
    +----+------+
    如果执行glance image-list命令出现以上画面则表示glance安装成功了。


    上传镜像
    [root@linux-node1 ~]# glance image-create --name "cirros" \
    > --file cirros-0.3.4-x86_64-disk.img \
    > --disk-format qcow2 --container-format bare \
    > --visibility public --progress
    [=============================>] 100%
    +------------------+--------------------------------------+
    | Property         | Value                                |
    +------------------+--------------------------------------+
    | checksum         | ee1eca47dc88f4879d8a229cc70a07c6     |
    | container_format | bare                                 |
    | created_at       | 2015-12-27T10:30:12Z                 |
    | disk_format      | qcow2                                |
    | id               | ad3eb543-166c-48bc-8e2b-fb6a853d9b06 |
    | min_disk         | 0                                    |
    | min_ram          | 0                                    |
    | name             | cirros                               |
    | owner            | f4dc313fb5164d99972355fe93a44045     |
    | protected        | False                                |
    | size             | 13287936                             |
    | status           | active                               |
    | tags             | []                                   |
    | updated_at       | 2015-12-27T10:30:12Z                 |
    | virtual_size     | None                                 |
    | visibility       | public                               |
    +------------------+--------------------------------------+
    查看镜像
    [root@linux-node1 ~]# glance image-list
    +--------------------------------------+--------+
    | ID                                   | Name   |
    +--------------------------------------+--------+
    | ad3eb543-166c-48bc-8e2b-fb6a853d9b06 | cirros |
    +--------------------------------------+--------+
    ###################################################################################################################
    Nova控制节点(openstack虚拟机必备组件:keystone,glance,nova,neutron)
    配置nova.conf文件
    [root@linux-node1 ~]# grep -n '^[a-z]'  /etc/nova/nova.conf
    61:rpc_backend=rabbit
    124:my_ip=192.168.56.11
    268:enabled_apis=osapi_compute,metadata
    425:auth_strategy=keystone
    1053:network_api_class=nova.network.neutronv2.api.API
    1171:linuxnet_interface_driver=nova.network.linux_net.NeutronLinuxBridgeInterfaceDriver
    1331:security_group_api=neutron
    1760:firewall_driver = nova.virt.firewall.NoopFirewallDriver
    1828:vncserver_listen=$my_ip
    1832:vncserver_proxyclient_address=$my_ip
    2213:connection=mysql://nova:nova@192.168.56.11/nova
    2334:host=$my_ip
    2542:auth_uri = http://192.168.56.11:5000
    2543:auth_url = http://192.168.56.11:35357
    2544:auth_plugin = password
    2545:project_domain_id = default
    2546:user_domain_id = default
    2547:project_name = service
    2548:username = nova
    2549:password = nova
    3033:url = http://192.168.56.11:9696
    3034:auth_url = http://192.168.56.11:35357
    3035:auth_plugin = password
    3036:project_domain_id = default
    3037:user_domain_id = default
    3038:region_name = RegionOne
    3039:project_name = service
    3040:username = neutron
    3041:password = neutron
    3049:service_metadata_proxy=true
    3053:metadata_proxy_shared_secret=neutron
    3804:lock_path=/var/lib/nova/tmp
    3967:rabbit_host=192.168.56.11
    3971:rabbit_port=5672
    3983:rabbit_userid=openstack
    3987:rabbit_password=openstack


    同步数据库
    [root@linux-node1 ~]# su -s /bin/sh -c "nova-manage db sync" nova
    [root@linux-node1 ~]# mysql -unova -pnova -h 192.168.56.11
    Welcome to the MariaDB monitor.  Commands end with ; or \g.
    Your MariaDB connection id is 37
    Server version: 5.5.44-MariaDB-log MariaDB Server


    Copyright (c) 2000, 2015, Oracle, MariaDB Corporation Ab and others.


    Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.


    MariaDB [(none)]> use nova
    Database changed
    MariaDB [nova]> show tables;
    +--------------------------------------------+
    | Tables_in_nova                             |
    +--------------------------------------------+
    | agent_builds                               |
    | aggregate_hosts                            |
    | aggregate_metadata                         |
    | aggregates                                 |
    | block_device_mapping                       |
    | bw_usage_cache                             |
    | cells                                      |
    | certificates                               |
    | compute_nodes                              |
    | console_pools                              |
    | consoles                                   |
    | dns_domains                                |
    | fixed_ips                                  |
    | floating_ips                               |
    | instance_actions                           |
    | instance_actions_events                    |
    | instance_extra                             |
    | instance_faults                            |
    | instance_group_member                      |
    | instance_group_policy                      |
    | instance_groups                            |
    | instance_id_mappings                       |
    | instance_info_caches                       |
    | instance_metadata                          |
    | instance_system_metadata                   |
    | instance_type_extra_specs                  |
    | instance_type_projects                     |
    | instance_types                             |
    | instances                                  |
    | key_pairs                                  |
    | migrate_version                            |
    | migrations                                 |
    | networks                                   |
    | pci_devices                                |
    | project_user_quotas                        |
    | provider_fw_rules                          |
    | quota_classes                              |
    | quota_usages                               |
    | quotas                                     |
    | reservations                               |
    | s3_images                                  |
    | security_group_default_rules               |
    | security_group_instance_association        |
    | security_group_rules                       |
    | security_groups                            |
    | services                                   |
    | shadow_agent_builds                        |
    | shadow_aggregate_hosts                     |
    | shadow_aggregate_metadata                  |
    | shadow_aggregates                          |
    | shadow_block_device_mapping                |
    | shadow_bw_usage_cache                      |
    | shadow_cells                               |
    | shadow_certificates                        |
    | shadow_compute_nodes                       |
    | shadow_console_pools                       |
    | shadow_consoles                            |
    | shadow_dns_domains                         |
    | shadow_fixed_ips                           |
    | shadow_floating_ips                        |
    | shadow_instance_actions                    |
    | shadow_instance_actions_events             |
    | shadow_instance_extra                      |
    | shadow_instance_faults                     |
    | shadow_instance_group_member               |
    | shadow_instance_group_policy               |
    | shadow_instance_groups                     |
    | shadow_instance_id_mappings                |
    | shadow_instance_info_caches                |
    | shadow_instance_metadata                   |
    | shadow_instance_system_metadata            |
    | shadow_instance_type_extra_specs           |
    | shadow_instance_type_projects              |
    | shadow_instance_types                      |
    | shadow_instances                           |
    | shadow_key_pairs                           |
    | shadow_migrate_version                     |
    | shadow_migrations                          |
    | shadow_networks                            |
    | shadow_pci_devices                         |
    | shadow_project_user_quotas                 |
    | shadow_provider_fw_rules                   |
    | shadow_quota_classes                       |
    | shadow_quota_usages                        |
    | shadow_quotas                              |
    | shadow_reservations                        |
    | shadow_s3_images                           |
    | shadow_security_group_default_rules        |
    | shadow_security_group_instance_association |
    | shadow_security_group_rules                |
    | shadow_security_groups                     |
    | shadow_services                            |
    | shadow_snapshot_id_mappings                |
    | shadow_snapshots                           |
    | shadow_task_log                            |
    | shadow_virtual_interfaces                  |
    | shadow_volume_id_mappings                  |
    | shadow_volume_usage_cache                  |
    | snapshot_id_mappings                       |
    | snapshots                                  |
    | tags                                       |
    | task_log                                   |
    | virtual_interfaces                         |
    | volume_id_mappings                         |
    | volume_usage_cache                         |
    +--------------------------------------------+
    105 rows in set (0.00 sec)


    [root@linux-node1 ~]# source admin-openrc.sh 
    [root@linux-node1 ~]# openstack user create --domain default --password=nova nova
    +-----------+----------------------------------+
    | Field     | Value                            |
    +-----------+----------------------------------+
    | domain_id | default                          |
    | enabled   | True                             |
    | id        | 8503f85364a34893af574b4b3e036aa1 |
    | name      | nova                             |
    +-----------+----------------------------------+
    [root@linux-node1 ~]# openstack role add --project service --user nova admin
    设置开机自启动
    [root@linux-node1 ~]# systemctl enable openstack-nova-api.service \
    > openstack-nova-cert.service openstack-nova-consoleauth.service \
    > openstack-nova-scheduler.service openstack-nova-conductor.service \
    > openstack-nova-novncproxy.service
    ln -s '/usr/lib/systemd/system/openstack-nova-api.service' '/etc/systemd/system/multi-user.target.wants/openstack-nova-api.service'
    ln -s '/usr/lib/systemd/system/openstack-nova-cert.service' '/etc/systemd/system/multi-user.target.wants/openstack-nova-cert.service'
    ln -s '/usr/lib/systemd/system/openstack-nova-consoleauth.service' '/etc/systemd/system/multi-user.target.wants/openstack-nova-consoleauth.service'
    ln -s '/usr/lib/systemd/system/openstack-nova-scheduler.service' '/etc/systemd/system/multi-user.target.wants/openstack-nova-scheduler.service'
    ln -s '/usr/lib/systemd/system/openstack-nova-conductor.service' '/etc/systemd/system/multi-user.target.wants/openstack-nova-conductor.service'
    ln -s '/usr/lib/systemd/system/openstack-nova-novncproxy.service' '/etc/systemd/system/multi-user.target.wants/openstack-nova-novncproxy.service'
    启动全部服务
    [root@linux-node1 ~]# systemctl start openstack-nova-api.service \
    > openstack-nova-cert.service openstack-nova-consoleauth.service \
    > openstack-nova-scheduler.service openstack-nova-conductor.service \
    > openstack-nova-novncproxy.service
    注册服务
    [root@linux-node1 ~]# openstack service create --name nova --description "OpenStack Compute" compute
    +-------------+----------------------------------+
    | Field       | Value                            |
    +-------------+----------------------------------+
    | description | OpenStack Compute                |
    | enabled     | True                             |
    | id          | e8fb4155650443a3a09796a3925c94d2 |
    | name        | nova                             |
    | type        | compute                          |
    +-------------+----------------------------------+
    [root@linux-node1 ~]# openstack endpoint create --region RegionOne compute public http://192.168.56.11:8774/v2/%\(tenant_id\)s
    +--------------+--------------------------------------------+
    | Field        | Value                                      |
    +--------------+--------------------------------------------+
    | enabled      | True                                       |
    | id           | ac483255b396403c9c3e4fedd4350465           |
    | interface    | public                                     |
    | region       | RegionOne                                  |
    | region_id    | RegionOne                                  |
    | service_id   | e8fb4155650443a3a09796a3925c94d2           |
    | service_name | nova                                       |
    | service_type | compute                                    |
    | url          | http://192.168.56.11:8774/v2/%(tenant_id)s |
    +--------------+--------------------------------------------+
    [root@linux-node1 ~]# openstack endpoint create --region RegionOne compute internal http://192.168.56.11:8774/v2/%\(tenant_id\)s
    +--------------+--------------------------------------------+
    | Field        | Value                                      |
    +--------------+--------------------------------------------+
    | enabled      | True                                       |
    | id           | 77f123d03e844f20abf05b18da65c675           |
    | interface    | internal                                   |
    | region       | RegionOne                                  |
    | region_id    | RegionOne                                  |
    | service_id   | e8fb4155650443a3a09796a3925c94d2           |
    | service_name | nova                                       |
    | service_type | compute                                    |
    | url          | http://192.168.56.11:8774/v2/%(tenant_id)s |
    +--------------+--------------------------------------------+
    [root@linux-node1 ~]# openstack endpoint create --region RegionOne compute admin http://192.168.56.11:8774/v2/%\(tenant_id\)s
    +--------------+--------------------------------------------+
    | Field        | Value                                      |
    +--------------+--------------------------------------------+
    | enabled      | True                                       |
    | id           | a185298ca9804a549f97da9236701773           |
    | interface    | admin                                      |
    | region       | RegionOne                                  |
    | region_id    | RegionOne                                  |
    | service_id   | e8fb4155650443a3a09796a3925c94d2           |
    | service_name | nova                                       |
    | service_type | compute                                    |
    | url          | http://192.168.56.11:8774/v2/%(tenant_id)s |
    +--------------+--------------------------------------------+


    验证是否成功
    [root@linux-node1 ~]# openstack host list
    +-------------+-------------+----------+
    | Host Name   | Service     | Zone     |
    +-------------+-------------+----------+
    | linux-node1 | scheduler   | internal |
    | linux-node1 | cert        | internal |
    | linux-node1 | conductor   | internal |
    | linux-node1 | consoleauth | internal |
    +-------------+-------------+----------+
    如果出现此四个服务则代表nova创建成功了
    ###################################################################################################################
    Nova计算节点
    nova-compute一般运行在计算节点上,通过message queue接收并管理VM的生命周期
    nova-compute通过libvirt管理KVM,通过XenAPI管理Xen
    [root@linux-node2 ~]# grep -n '^[a-z]' /etc/nova/nova.conf 
    61:rpc_backend=rabbit
    124:my_ip=192.168.56.12
    268:enabled_apis=osapi_compute,metadata
    425:auth_strategy=keystone
    1053:network_api_class=nova.network.neutronv2.api.API
    1171:linuxnet_interface_driver=nova.network.linux_net.NeutronLinuxBridgeInterfaceDriver
    1331:security_group_api=neutron
    1760:firewall_driver = nova.virt.firewall.NoopFirewallDriver
    1820:novncproxy_base_url=http://192.168.56.11:6080/vnc_auto.html
    1828:vncserver_listen=0.0.0.0
    1832:vncserver_proxyclient_address=192.168.56.12
    1835:vnc_enabled=true
    1838:vnc_keymap=en-us
    2213:connection=mysql://nova:nova@192.168.56.11/nova
    2334:host=192.168.56.11
    2542:auth_uri = http://192.168.56.11:5000
    2543:auth_url = http://192.168.56.11:35357
    2544:auth_plugin = password
    2545:project_domain_id = default
    2546:user_domain_id = default
    2547:project_name = service
    2548:username = nova
    2549:password = nova
    2727:virt_type=kvm
    3033:url = http://192.168.56.11:9696
    3034:auth_url = http://192.168.56.11:35357
    3035:auth_plugin = password
    3036:project_domain_id = default
    3037:user_domain_id = default
    3038:region_name = RegionOne
    3039:project_name = service
    3040:username = neutron
    3041:password = neutron
    3804:lock_path=/var/lib/nova/tmp
    3967:rabbit_host=192.168.56.11
    3971:rabbit_port=5672
    3983:rabbit_userid=openstack
    3987:rabbit_password=openstack


    [root@linux-node2 ~]# systemctl enable libvirtd openstack-nova-compute
    Created symlink from /etc/systemd/system/multi-user.target.wants/openstack-nova-compute.service to /usr/lib/systemd/system/openstack-nova-compute.service.
    [root@linux-node2 ~]# systemctl start libvirtd openstack-nova-compute
    ######################################################################################################################
    然后在linux-node1上面查看注册状态
    [root@linux-node1 ~]# openstack host list
    +-------------+-------------+----------+
    | Host Name   | Service     | Zone     |
    +-------------+-------------+----------+
    | linux-node1 | scheduler   | internal |
    | linux-node1 | cert        | internal |
    | linux-node1 | conductor   | internal |
    | linux-node1 | consoleauth | internal |
    | linux-node2 | compute     | nova     |
    +-------------+-------------+----------+
    计算节点上nova安装成功并注册成功


    镜像出于活动的状态
    [root@linux-node1 ~]# nova image-list
    +--------------------------------------+--------+--------+--------+
    | ID                                   | Name   | Status | Server |
    +--------------------------------------+--------+--------+--------+
    | ad3eb543-166c-48bc-8e2b-fb6a853d9b06 | cirros | ACTIVE |        |
    +--------------------------------------+--------+--------+--------+


    验证nova与keystone的连接,如下说明成功
    [root@linux-node1 ~]# nova endpoints
    WARNING: glance has no endpoint in ! Available endpoints for this service:
    +-----------+----------------------------------+
    | glance    | Value                            |
    +-----------+----------------------------------+
    | id        | 36da860e8a764037ae36de815aadcc84 |
    | interface | public                           |
    | region    | RegionOne                        |
    | region_id | RegionOne                        |
    | url       | http://192.168.56.11:9292        |
    +-----------+----------------------------------+
    +-----------+----------------------------------+
    | glance    | Value                            |
    +-----------+----------------------------------+
    | id        | 907c268057db4cb3a4f5d50379b5ca47 |
    | interface | admin                            |
    | region    | RegionOne                        |
    | region_id | RegionOne                        |
    | url       | http://192.168.56.11:9292        |
    +-----------+----------------------------------+
    +-----------+----------------------------------+
    | glance    | Value                            |
    +-----------+----------------------------------+
    | id        | f58155e69a814ef68b395bf9493ec525 |
    | interface | internal                         |
    | region    | RegionOne                        |
    | region_id | RegionOne                        |
    | url       | http://192.168.56.11:9292        |
    +-----------+----------------------------------+
    WARNING: nova has no endpoint in ! Available endpoints for this service:
    +-----------+---------------------------------------------------------------+
    | nova      | Value                                                         |
    +-----------+---------------------------------------------------------------+
    | id        | 77f123d03e844f20abf05b18da65c675                              |
    | interface | internal                                                      |
    | region    | RegionOne                                                     |
    | region_id | RegionOne                                                     |
    | url       | http://192.168.56.11:8774/v2/f4dc313fb5164d99972355fe93a44045 |
    +-----------+---------------------------------------------------------------+
    +-----------+---------------------------------------------------------------+
    | nova      | Value                                                         |
    +-----------+---------------------------------------------------------------+
    | id        | a185298ca9804a549f97da9236701773                              |
    | interface | admin                                                         |
    | region    | RegionOne                                                     |
    | region_id | RegionOne                                                     |
    | url       | http://192.168.56.11:8774/v2/f4dc313fb5164d99972355fe93a44045 |
    +-----------+---------------------------------------------------------------+
    +-----------+---------------------------------------------------------------+
    | nova      | Value                                                         |
    +-----------+---------------------------------------------------------------+
    | id        | ac483255b396403c9c3e4fedd4350465                              |
    | interface | public                                                        |
    | region    | RegionOne                                                     |
    | region_id | RegionOne                                                     |
    | url       | http://192.168.56.11:8774/v2/f4dc313fb5164d99972355fe93a44045 |
    +-----------+---------------------------------------------------------------+
    WARNING: keystone has no endpoint in ! Available endpoints for this service:
    +-----------+----------------------------------+
    | keystone  | Value                            |
    +-----------+----------------------------------+
    | id        | c63a949ecdf248b68f1e714e94d238ba |
    | interface | admin                            |
    | region    | RegionOne                        |
    | region_id | RegionOne                        |
    | url       | http://192.168.56.11:35357/v2.0  |
    +-----------+----------------------------------+
    +-----------+----------------------------------+
    | keystone  | Value                            |
    +-----------+----------------------------------+
    | id        | c6ca8b1002ac4fb581295d8ed62b0951 |
    | interface | internal                         |
    | region    | RegionOne                        |
    | region_id | RegionOne                        |
    | url       | http://192.168.56.11:5000/v2.0   |
    +-----------+----------------------------------+
    +-----------+----------------------------------+
    | keystone  | Value                            |
    +-----------+----------------------------------+
    | id        | e806479ecc114442b23360142b85bde6 |
    | interface | public                           |
    | region    | RegionOne                        |
    | region_id | RegionOne                        |
    | url       | http://192.168.56.11:5000/v2.0   |
    +-----------+----------------------------------+
    ###################################################################################################################
    Neutron部署
    注册网络服务
    [root@linux-node1 ~]# openstack service create --name neutron --description "OpenStack Networking" network
    +-------------+----------------------------------+
    | Field       | Value                            |
    +-------------+----------------------------------+
    | description | OpenStack Networking             |
    | enabled     | True                             |
    | id          | 3984fda1dd02410ca60d29d5ba2200fd |
    | name        | neutron                          |
    | type        | network                          |
    +-------------+----------------------------------+
    [root@linux-node1 ~]# openstack endpoint create --region RegionOne network public http://192.168.56.11:9696
    +--------------+----------------------------------+
    | Field        | Value                            |
    +--------------+----------------------------------+
    | enabled      | True                             |
    | id           | ee4ceeb3619041f186e45a9ff092b7d2 |
    | interface    | public                           |
    | region       | RegionOne                        |
    | region_id    | RegionOne                        |
    | service_id   | 3984fda1dd02410ca60d29d5ba2200fd |
    | service_name | neutron                          |
    | service_type | network                          |
    | url          | http://192.168.56.11:9696        |
    +--------------+----------------------------------+
    [root@linux-node1 ~]# openstack endpoint create --region RegionOne network internal http://192.168.56.11:9696
    +--------------+----------------------------------+
    | Field        | Value                            |
    +--------------+----------------------------------+
    | enabled      | True                             |
    | id           | 337595b0538044478ba592c90af8b7c9 |
    | interface    | internal                         |
    | region       | RegionOne                        |
    | region_id    | RegionOne                        |
    | service_id   | 3984fda1dd02410ca60d29d5ba2200fd |
    | service_name | neutron                          |
    | service_type | network                          |
    | url          | http://192.168.56.11:9696        |
    +--------------+----------------------------------+
    [root@linux-node1 ~]# openstack endpoint create --region RegionOne network admin http://192.168.56.11:9696
    +--------------+----------------------------------+
    | Field        | Value                            |
    +--------------+----------------------------------+
    | enabled      | True                             |
    | id           | 458b7c8f4dde4890b5046184844b462a |
    | interface    | admin                            |
    | region       | RegionOne                        |
    | region_id    | RegionOne                        |
    | service_id   | 3984fda1dd02410ca60d29d5ba2200fd |
    | service_name | neutron                          |
    | service_type | network                          |
    | url          | http://192.168.56.11:9696        |
    +--------------+----------------------------------+


    [root@linux-node1 ~]# grep -n '^[a-z]' /etc/neutron/neutron.conf 
    20:state_path = /var/lib/neutron
    60:core_plugin = ml2
    77:service_plugins = router
    92:auth_strategy = keystone
    360:notify_nova_on_port_status_changes = True
    364:notify_nova_on_port_data_changes = True
    367:nova_url = http://192.168.56.11:8774/v2
    573:rpc_backend=rabbit
    717:auth_uri = http://192.168.56.11:5000
    718:auth_url = http://192.168.56.11:35357
    719:auth_plugin = password
    720:project_domain_id = default
    721:user_domain_id = default
    722:project_name = service
    723:username = neutron
    724:password = neutron
    737:connection = mysql://neutron:neutron@192.168.56.11:3306/neutron
    780:auth_url = http://192.168.56.11:35357
    781:auth_plugin = password
    782:project_domain_id = default
    783:user_domain_id = default
    784:region_name = RegionOne
    785:project_name = service
    786:username = nova
    787:password = nova
    818:lock_path = $state_path/lock
    998:rabbit_host = 192.168.56.11
    1002:rabbit_port = 5672
    1014:rabbit_userid = openstack
    1018:rabbit_password = openstack


    [root@linux-node1 ~]# grep -n '^[a-z]' /etc/neutron/plugins/ml2/ml2_conf.ini
    5:type_drivers = flat,vlan,gre,vxlan,geneve
    12:tenant_network_types = vlan,gre,vxlan,geneve
    18:mechanism_drivers = openvswitch,linuxbridge
    27:extension_drivers = port_security
    67:flat_networks = physnet1
    120:enable_ipset = True


    [root@linux-node1 ~]# grep -n '^[a-z]' /etc/neutron/plugins/ml2/linuxbridge_agent.ini
    9:physical_interface_mappings = physnet1:eth0
    16:enable_vxlan = false
    51:prevent_arp_spoofing = True
    57:firewall_driver = neutron.agent.linux.iptables_firewall.IptablesFirewallDriver
    61:enable_security_group = True


    [root@linux-node1 ~]# grep -n '^[a-z]' /etc/neutron/dhcp_agent.ini
    27:interface_driver = neutron.agent.linux.interface.BridgeInterfaceDriver
    31:dhcp_driver = neutron.agent.linux.dhcp.Dnsmasq
    52:enable_isolated_metadata = true


    [root@linux-node1 ~]# grep -n '^[a-z]' /etc/neutron/metadata_agent.ini
    4:auth_uri = http://192.168.56.11:5000
    5:auth_url = http://192.168.56.11:35357
    6:auth_region = RegionOne
    7:auth_plugin = password
    8:project_domain_id = default
    9:user_domain_id = default
    10:project_name = service
    11:username = neutron
    12:password = neutron
    29:nova_metadata_ip = 192.168.56.11
    52:metadata_proxy_shared_secret = neutron


    [root@linux-node1 ~]# grep -n '^[a-z]' /etc/nova/nova.conf 
    61:rpc_backend=rabbit
    124:my_ip=192.168.56.11
    268:enabled_apis=osapi_compute,metadata
    425:auth_strategy=keystone
    1053:network_api_class=nova.network.neutronv2.api.API
    1171:linuxnet_interface_driver=nova.network.linux_net.NeutronLinuxBridgeInterfaceDriver
    1331:security_group_api=neutron
    1760:firewall_driver = nova.virt.firewall.NoopFirewallDriver
    1828:vncserver_listen=$my_ip
    1832:vncserver_proxyclient_address=$my_ip
    2213:connection=mysql://nova:nova@192.168.56.11/nova
    2334:host=$my_ip
    2542:auth_uri = http://192.168.56.11:5000
    2543:auth_url = http://192.168.56.11:35357
    2544:auth_plugin = password
    2545:project_domain_id = default
    2546:user_domain_id = default
    2547:project_name = service
    2548:username = nova
    2549:password = nova
    3033:url = http://192.168.56.11:9696
    3034:auth_url = http://192.168.56.11:35357
    3035:auth_plugin = password
    3036:project_domain_id = default
    3037:user_domain_id = default
    3038:region_name = RegionOne
    3039:project_name = service
    3040:username = neutron
    3041:password = neutron
    3049:service_metadata_proxy=true
    3053:metadata_proxy_shared_secret=neutron
    3804:lock_path=/var/lib/nova/tmp
    3967:rabbit_host=192.168.56.11
    3971:rabbit_port=5672
    3983:rabbit_userid=openstack
    3987:rabbit_password=openstack


    [root@linux-node1 ~]# ln -s /etc/neutron/plugins/ml2/ml2_conf.ini /etc/neutron/plugin.ini


    [root@linux-node1 ~]# openstack user create --domain default --password=neutron neutron
    +-----------+----------------------------------+
    | Field     | Value                            |
    +-----------+----------------------------------+
    | domain_id | default                          |
    | enabled   | True                             |
    | id        | 28fb100f0efc4d648344614458e1bf7e |
    | name      | neutron                          |
    +-----------+----------------------------------+
    [root@linux-node1 ~]# openstack role add --project service --user neutron admin


    更新数据库
    [root@linux-node1 ~]# openstack role add --project service --user neutron admin
    [root@linux-node1 ~]# su -s /bin/sh -c "neutron-db-manage --config-file /etc/neutron/neutron.conf \
    > --config-file /etc/neutron/plugins/ml2/ml2_conf.ini upgrade head" neutron
    No handlers could be found for logger "neutron.quota"
    INFO  [alembic.runtime.migration] Context impl MySQLImpl.
    INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
      Running upgrade for neutron ...
    INFO  [alembic.runtime.migration] Context impl MySQLImpl.
    INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
    INFO  [alembic.runtime.migration] Running upgrade  -> juno, juno_initial
    INFO  [alembic.runtime.migration] Running upgrade juno -> 44621190bc02, add_uniqueconstraint_ipavailability_ranges
    INFO  [alembic.runtime.migration] Running upgrade 44621190bc02 -> 1f71e54a85e7, ml2_network_segments models change for multi-segment network.
    INFO  [alembic.runtime.migration] Running upgrade 1f71e54a85e7 -> 408cfbf6923c, remove ryu plugin
    INFO  [alembic.runtime.migration] Running upgrade 408cfbf6923c -> 28c0ffb8ebbd, remove mlnx plugin
    INFO  [alembic.runtime.migration] Running upgrade 28c0ffb8ebbd -> 57086602ca0a, scrap_nsx_adv_svcs_models
    INFO  [alembic.runtime.migration] Running upgrade 57086602ca0a -> 38495dc99731, ml2_tunnel_endpoints_table
    INFO  [alembic.runtime.migration] Running upgrade 38495dc99731 -> 4dbe243cd84d, nsxv
    INFO  [alembic.runtime.migration] Running upgrade 4dbe243cd84d -> 41662e32bce2, L3 DVR SNAT mapping
    INFO  [alembic.runtime.migration] Running upgrade 41662e32bce2 -> 2a1ee2fb59e0, Add mac_address unique constraint
    INFO  [alembic.runtime.migration] Running upgrade 2a1ee2fb59e0 -> 26b54cf9024d, Add index on allocated
    INFO  [alembic.runtime.migration] Running upgrade 26b54cf9024d -> 14be42f3d0a5, Add default security group table
    INFO  [alembic.runtime.migration] Running upgrade 14be42f3d0a5 -> 16cdf118d31d, extra_dhcp_options IPv6 support
    INFO  [alembic.runtime.migration] Running upgrade 16cdf118d31d -> 43763a9618fd, add mtu attributes to network
    INFO  [alembic.runtime.migration] Running upgrade 43763a9618fd -> bebba223288, Add vlan transparent property to network
    INFO  [alembic.runtime.migration] Running upgrade bebba223288 -> 4119216b7365, Add index on tenant_id column
    INFO  [alembic.runtime.migration] Running upgrade 4119216b7365 -> 2d2a8a565438, ML2 hierarchical binding
    INFO  [alembic.runtime.migration] Running upgrade 2d2a8a565438 -> 2b801560a332, Remove Hyper-V Neutron Plugin
    INFO  [alembic.runtime.migration] Running upgrade 2b801560a332 -> 57dd745253a6, nuage_kilo_migrate
    INFO  [alembic.runtime.migration] Running upgrade 57dd745253a6 -> f15b1fb526dd, Cascade Floating IP Floating Port deletion
    INFO  [alembic.runtime.migration] Running upgrade f15b1fb526dd -> 341ee8a4ccb5, sync with cisco repo
    INFO  [alembic.runtime.migration] Running upgrade 341ee8a4ccb5 -> 35a0f3365720, add port-security in ml2
    INFO  [alembic.runtime.migration] Running upgrade 35a0f3365720 -> 1955efc66455, weight_scheduler
    INFO  [alembic.runtime.migration] Running upgrade 1955efc66455 -> 51c54792158e, Initial operations for subnetpools
    INFO  [alembic.runtime.migration] Running upgrade 51c54792158e -> 589f9237ca0e, Cisco N1kv ML2 driver tables
    INFO  [alembic.runtime.migration] Running upgrade 589f9237ca0e -> 20b99fd19d4f, Cisco UCS Manager Mechanism Driver
    INFO  [alembic.runtime.migration] Running upgrade 20b99fd19d4f -> 034883111f, Remove allow_overlap from subnetpools
    INFO  [alembic.runtime.migration] Running upgrade 034883111f -> 268fb5e99aa2, Initial operations in support of subnet allocation from a pool
    INFO  [alembic.runtime.migration] Running upgrade 268fb5e99aa2 -> 28a09af858a8, Initial operations to support basic quotas on prefix space in a subnet pool
    INFO  [alembic.runtime.migration] Running upgrade 28a09af858a8 -> 20c469a5f920, add index for port
    INFO  [alembic.runtime.migration] Running upgrade 20c469a5f920 -> kilo, kilo
    INFO  [alembic.runtime.migration] Running upgrade kilo -> 354db87e3225, nsxv_vdr_metadata.py
    INFO  [alembic.runtime.migration] Running upgrade 354db87e3225 -> 599c6a226151, neutrodb_ipam
    INFO  [alembic.runtime.migration] Running upgrade 599c6a226151 -> 52c5312f6baf, Initial operations in support of address scopes
    INFO  [alembic.runtime.migration] Running upgrade 52c5312f6baf -> 313373c0ffee, Flavor framework
    INFO  [alembic.runtime.migration] Running upgrade 313373c0ffee -> 8675309a5c4f, network_rbac
    INFO  [alembic.runtime.migration] Running upgrade kilo -> 30018084ec99, Initial no-op Liberty contract rule.
    INFO  [alembic.runtime.migration] Running upgrade 30018084ec99, 8675309a5c4f -> 4ffceebfada, network_rbac
    INFO  [alembic.runtime.migration] Running upgrade 4ffceebfada -> 5498d17be016, Drop legacy OVS and LB plugin tables
    INFO  [alembic.runtime.migration] Running upgrade 5498d17be016 -> 2a16083502f3, Metaplugin removal
    INFO  [alembic.runtime.migration] Running upgrade 2a16083502f3 -> 2e5352a0ad4d, Add missing foreign keys
    INFO  [alembic.runtime.migration] Running upgrade 2e5352a0ad4d -> 11926bcfe72d, add geneve ml2 type driver
    INFO  [alembic.runtime.migration] Running upgrade 11926bcfe72d -> 4af11ca47297, Drop cisco monolithic tables
    INFO  [alembic.runtime.migration] Running upgrade 8675309a5c4f -> 45f955889773, quota_usage
    INFO  [alembic.runtime.migration] Running upgrade 45f955889773 -> 26c371498592, subnetpool hash
    INFO  [alembic.runtime.migration] Running upgrade 26c371498592 -> 1c844d1677f7, add order to dnsnameservers
    INFO  [alembic.runtime.migration] Running upgrade 1c844d1677f7 -> 1b4c6e320f79, address scope support in subnetpool
    INFO  [alembic.runtime.migration] Running upgrade 1b4c6e320f79 -> 48153cb5f051, qos db changes
    INFO  [alembic.runtime.migration] Running upgrade 48153cb5f051 -> 9859ac9c136, quota_reservations
    INFO  [alembic.runtime.migration] Running upgrade 9859ac9c136 -> 34af2b5c5a59, Add dns_name to Port
      OK
     
    重新驱动下服务:
    [root@linux-node1 ~]# systemctl restart openstack-nova-api
    开机自动加载neutron及启动neutron服务
    [root@linux-node1 ~]# systemctl enable neutron-server.service \
    >   neutron-linuxbridge-agent.service neutron-dhcp-agent.service \
    >   neutron-metadata-agent.service
    ln -s '/usr/lib/systemd/system/neutron-server.service' '/etc/systemd/system/multi-user.target.wants/neutron-server.service'
    ln -s '/usr/lib/systemd/system/neutron-linuxbridge-agent.service' '/etc/systemd/system/multi-user.target.wants/neutron-linuxbridge-agent.service'
    ln -s '/usr/lib/systemd/system/neutron-dhcp-agent.service' '/etc/systemd/system/multi-user.target.wants/neutron-dhcp-agent.service'
    ln -s '/usr/lib/systemd/system/neutron-metadata-agent.service' '/etc/systemd/system/multi-user.target.wants/neutron-metadata-agent.service'
    [root@linux-node1 ~]# systemctl restart neutron-server.service \
    >   neutron-linuxbridge-agent.service neutron-dhcp-agent.service \
    >   neutron-metadata-agent.service


    查看网卡的配置
    [root@linux-node1 ~]# neutron agent-list 
    +--------------------------------------+--------------------+-------------+-------+----------------+---------------------------+
    | id                                   | agent_type         | host        | alive | admin_state_up | binary                    |
    +--------------------------------------+--------------------+-------------+-------+----------------+---------------------------+
    | 6f8de3d4-09e7-4824-a469-ad3a6de45a20 | Linux bridge agent | linux-node1 | :-)   | True           | neutron-linuxbridge-agent |
    | 7666c62c-f400-4528-9978-b1efbe0e8f6a | Metadata agent     | linux-node1 | :-)   | True           | neutron-metadata-agent    |
    | d3901d1a-6cda-444c-b501-e46c55b2c5b3 | DHCP agent         | linux-node1 | :-)   | True           | neutron-dhcp-agent        |
    +--------------------------------------+--------------------+-------------+-------+----------------+---------------------------+


    ###############################################################################################################
    计算节点:(将neutron的配置文件拷贝到计算节点)
    [root@linux-node2 ~]# grep -n '^[a-z]'  /etc/neutron/neutron.conf
    20:state_path = /var/lib/neutron
    60:core_plugin = ml2
    77:service_plugins = router
    92:auth_strategy = keystone
    360:notify_nova_on_port_status_changes = True
    364:notify_nova_on_port_data_changes = True
    367:nova_url = http://192.168.56.11:8774/v2
    573:rpc_backend=rabbit
    717:auth_uri = http://192.168.56.11:5000
    718:auth_url = http://192.168.56.11:35357
    719:auth_plugin = password
    720:project_domain_id = default
    721:user_domain_id = default
    722:project_name = service
    723:username = neutron
    724:password = neutron
    737:connection = mysql://neutron:neutron@192.168.56.11:3306/neutron
    780:auth_url = http://192.168.56.11:35357
    781:auth_plugin = password
    782:project_domain_id = default
    783:user_domain_id = default
    784:region_name = RegionOne
    785:project_name = service
    786:username = nova
    787:password = nova
    818:lock_path = $state_path/lock
    998:rabbit_host = 192.168.56.11
    1002:rabbit_port = 5672
    1014:rabbit_userid = openstack
    1018:rabbit_password = openstack


    [root@linux-node2 ~]# grep -n '^[a-z]'  /etc/neutron/plugins/ml2/linuxbridge_agent.ini
    9:physical_interface_mappings = physnet1:eth0
    16:enable_vxlan = false
    51:prevent_arp_spoofing = True
    57:firewall_driver = neutron.agent.linux.iptables_firewall.IptablesFirewallDriver
    61:enable_security_group = True


    [root@linux-node2 ~]# grep -n '^[a-z]'  /etc/neutron/plugins/ml2/ml2_conf.ini
    5:type_drivers = flat,vlan,gre,vxlan,geneve
    12:tenant_network_types = vlan,gre,vxlan,geneve
    18:mechanism_drivers = openvswitch,linuxbridge
    27:extension_drivers = port_security
    67:flat_networks = physnet1
    120:enable_ipset = True


    [root@linux-node2 ~]# grep -n '^[a-z]'  /etc/nova/nova.conf 
    61:rpc_backend=rabbit
    124:my_ip=192.168.56.12
    268:enabled_apis=osapi_compute,metadata
    425:auth_strategy=keystone
    1053:network_api_class=nova.network.neutronv2.api.API
    1171:linuxnet_interface_driver=nova.network.linux_net.NeutronLinuxBridgeInterfaceDriver
    1331:security_group_api=neutron
    1760:firewall_driver = nova.virt.firewall.NoopFirewallDriver
    1820:novncproxy_base_url=http://192.168.56.11:6080/vnc_auto.html
    1828:vncserver_listen=0.0.0.0
    1832:vncserver_proxyclient_address=192.168.56.12
    1835:vnc_enabled=true
    1838:vnc_keymap=en-us
    2213:connection=mysql://nova:nova@192.168.56.11/nova
    2334:host=192.168.56.11
    2542:auth_uri = http://192.168.56.11:5000
    2543:auth_url = http://192.168.56.11:35357
    2544:auth_plugin = password
    2545:project_domain_id = default
    2546:user_domain_id = default
    2547:project_name = service
    2548:username = nova
    2549:password = nova
    2727:virt_type=kvm
    3033:url = http://192.168.56.11:9696
    3034:auth_url = http://192.168.56.11:35357
    3035:auth_plugin = password
    3036:project_domain_id = default
    3037:user_domain_id = default
    3038:region_name = RegionOne
    3039:project_name = service
    3040:username = neutron
    3041:password = neutron
    3804:lock_path=/var/lib/nova/tmp
    3967:rabbit_host=192.168.56.11
    3971:rabbit_port=5672
    3983:rabbit_userid=openstack
    3987:rabbit_password=openstack


    [root@linux-node2 ~]# systemctl restart openstack-nova-compute
    [root@linux-node2 ~]# ln -s /etc/neutron/plugins/ml2/ml2_conf.ini /etc/neutron/plugin.ini
    [root@linux-node2 ~]# systemctl enable neutron-linuxbridge-agent.service
    Created symlink from /etc/systemd/system/multi-user.target.wants/neutron-linuxbridge-agent.service to /usr/lib/systemd/system/neutron-linuxbridge-agent.service.
    [root@linux-node2 ~]# systemctl restart neutron-linuxbridge-agent.service
    在控制节点查看
    [root@linux-node1 ~]# neutron agent-list
    +--------------------------------------+--------------------+-------------+-------+----------------+---------------------------+
    | id                                   | agent_type         | host        | alive | admin_state_up | binary                    |
    +--------------------------------------+--------------------+-------------+-------+----------------+---------------------------+
    | 6f8de3d4-09e7-4824-a469-ad3a6de45a20 | Linux bridge agent | linux-node1 | :-)   | True           | neutron-linuxbridge-agent |
    | 7666c62c-f400-4528-9978-b1efbe0e8f6a | Metadata agent     | linux-node1 | :-)   | True           | neutron-metadata-agent    |
    | 8d54c032-699e-4149-8980-284b127b08b2 | Linux bridge agent | linux-node2 | :-)   | True           | neutron-linuxbridge-agent |
    | d3901d1a-6cda-444c-b501-e46c55b2c5b3 | DHCP agent         | linux-node1 | :-)   | True           | neutron-dhcp-agent        |
    +--------------------------------------+--------------------+-------------+-------+----------------+---------------------------+
    代表计算节点的Linux bridge agent已成功连接到控制节点。
    #####################################################################################################################################


    创建一个网络
    [root@linux-node1 ~]# neutron net-create flat --shared --provider:physical_network physnet1 --provider:network_type flat
    Created a new network:
    +---------------------------+--------------------------------------+
    | Field                     | Value                                |
    +---------------------------+--------------------------------------+
    | admin_state_up            | True                                 |
    | id                        | 5eb49e52-08a9-4a12-9454-b3188a140a21 |
    | mtu                       | 0                                    |
    | name                      | flat                                 |
    | port_security_enabled     | True                                 |
    | provider:network_type     | flat                                 |
    | provider:physical_network | physnet1                             |
    | provider:segmentation_id  |                                      |
    | router:external           | False                                |
    | shared                    | True                                 |
    | status                    | ACTIVE                               |
    | subnets                   |                                      |
    | tenant_id                 | f4dc313fb5164d99972355fe93a44045     |
    +---------------------------+--------------------------------------+
    创建一个子网
    [root@linux-node1 ~]# neutron subnet-create flat 192.168.56.0/24 --name flat-subnet --allocation-pool start=192.168.56.100,end=192.168.56.200 --dns-nameserver 192.168.56.2 --gateway 192.168.56.2
    Created a new subnet:
    +-------------------+------------------------------------------------------+
    | Field             | Value                                                |
    +-------------------+------------------------------------------------------+
    | allocation_pools  | {"start": "192.168.56.100", "end": "192.168.56.200"} |
    | cidr              | 192.168.56.0/24                                      |
    | dns_nameservers   | 192.168.56.2                                         |
    | enable_dhcp       | True                                                 |
    | gateway_ip        | 192.168.56.2                                         |
    | host_routes       |                                                      |
    | id                | 1196139b-c975-410c-a038-d2889ec8f255                 |
    | ip_version        | 4                                                    |
    | ipv6_address_mode |                                                      |
    | ipv6_ra_mode      |                                                      |
    | name              | flat-subnet                                          |
    | network_id        | 5eb49e52-08a9-4a12-9454-b3188a140a21                 |
    | subnetpool_id     |                                                      |
    | tenant_id         | f4dc313fb5164d99972355fe93a44045                     |
    +-------------------+------------------------------------------------------+
    查看网络和子网
    [root@linux-node1 ~]# neutron subnet-list 
    +--------------------------------------+-------------+-----------------+------------------------------------------------------+
    | id                                   | name        | cidr            | allocation_pools                                     |
    +--------------------------------------+-------------+-----------------+------------------------------------------------------+
    | 1196139b-c975-410c-a038-d2889ec8f255 | flat-subnet | 192.168.56.0/24 | {"start": "192.168.56.100", "end": "192.168.56.200"} |
    +--------------------------------------+-------------+-----------------+------------------------------------------------------+
    [root@linux-node1 ~]# source demo-openrc.sh 
    [root@linux-node1 ~]# ssh-keygen -q -N ""
    Enter file in which to save the key (/root/.ssh/id_rsa): 
    [root@linux-node1 ~]# nova keypair-add --pub-key .ssh/id_rsa.pub mykey
    [root@linux-node1 ~]# nova keypair-list 
    +-------+-------------------------------------------------+
    | Name  | Fingerprint                                     |
    +-------+-------------------------------------------------+
    | mykey | de:1e:9d:2b:2e:aa:a9:3d:6d:e4:9e:62:7b:16:34:a5 |
    +-------+-------------------------------------------------+
    加2个安全组
    [root@linux-node1 ~]# nova secgroup-add-rule default icmp -1 -1 0.0.0.0/0
    +-------------+-----------+---------+-----------+--------------+
    | IP Protocol | From Port | To Port | IP Range  | Source Group |
    +-------------+-----------+---------+-----------+--------------+
    | icmp        | -1        | -1      | 0.0.0.0/0 |              |
    +-------------+-----------+---------+-----------+--------------+
    [root@linux-node1 ~]# nova secgroup-add-rule default tcp 22 22 0.0.0.0/0
    +-------------+-----------+---------+-----------+--------------+
    | IP Protocol | From Port | To Port | IP Range  | Source Group |
    +-------------+-----------+---------+-----------+--------------+
    | tcp         | 22        | 22      | 0.0.0.0/0 |              |
    +-------------+-----------+---------+-----------+--------------+
    查看虚拟机类型
    [root@linux-node1 ~]# nova flavor-list
    +----+-----------+-----------+------+-----------+------+-------+-------------+-----------+
    | ID | Name      | Memory_MB | Disk | Ephemeral | Swap | VCPUs | RXTX_Factor | Is_Public |
    +----+-----------+-----------+------+-----------+------+-------+-------------+-----------+
    | 1  | m1.tiny   | 512       | 1    | 0         |      | 1     | 1.0         | True      |
    | 2  | m1.small  | 2048      | 20   | 0         |      | 1     | 1.0         | True      |
    | 3  | m1.medium | 4096      | 40   | 0         |      | 2     | 1.0         | True      |
    | 4  | m1.large  | 8192      | 80   | 0         |      | 4     | 1.0         | True      |
    | 5  | m1.xlarge | 16384     | 160  | 0         |      | 8     | 1.0         | True      |
    +----+-----------+-----------+------+-----------+------+-------+-------------+-----------+
    镜像
    [root@linux-node1 ~]# nova image-list
    +--------------------------------------+--------+--------+--------+
    | ID                                   | Name   | Status | Server |
    +--------------------------------------+--------+--------+--------+
    | ad3eb543-166c-48bc-8e2b-fb6a853d9b06 | cirros | ACTIVE |        |
    +--------------------------------------+--------+--------+--------+
    网络
    [root@linux-node1 ~]# neutron net-list
    +--------------------------------------+------+------------------------------------------------------+
    | id                                   | name | subnets                                              |
    +--------------------------------------+------+------------------------------------------------------+
    | 5eb49e52-08a9-4a12-9454-b3188a140a21 | flat | 1196139b-c975-410c-a038-d2889ec8f255 192.168.56.0/24 |
    +--------------------------------------+------+------------------------------------------------------+
    安全组
    [root@linux-node1 ~]# nova secgroup-list
    +--------------------------------------+---------+------------------------+
    | Id                                   | Name    | Description            |
    +--------------------------------------+---------+------------------------+
    | 715e16c4-a3b7-4121-a4c1-e44c0995063f | default | Default security group |
    +--------------------------------------+---------+------------------------+
    创建虚拟机
    [root@linux-node1 ~]# nova boot --flavor m1.tiny --image cirros --nic net-id=5eb49e52-08a9-4a12-9454-b3188a140a21 --security-group default --key-name mykey hello-instance
    +--------------------------------------+-----------------------------------------------+
    | Property                             | Value                                         |
    +--------------------------------------+-----------------------------------------------+
    | OS-DCF:diskConfig                    | MANUAL                                        |
    | OS-EXT-AZ:availability_zone          |                                               |
    | OS-EXT-STS:power_state               | 0                                             |
    | OS-EXT-STS:task_state                | scheduling                                    |
    | OS-EXT-STS:vm_state                  | building                                      |
    | OS-SRV-USG:launched_at               | -                                             |
    | OS-SRV-USG:terminated_at             | -                                             |
    | accessIPv4                           |                                               |
    | accessIPv6                           |                                               |
    | adminPass                            | mHWxqJuqxG4b                                  |
    | config_drive                         |                                               |
    | created                              | 2015-12-27T12:57:33Z                          |
    | flavor                               | m1.tiny (1)                                   |
    | hostId                               |                                               |
    | id                                   | 0723632f-18a0-4f61-9dd0-17e1aa97920d          |
    | image                                | cirros (ad3eb543-166c-48bc-8e2b-fb6a853d9b06) |
    | key_name                             | mykey                                         |
    | metadata                             | {}                                            |
    | name                                 | hello-instance                                |
    | os-extended-volumes:volumes_attached | []                                            |
    | progress                             | 0                                             |
    | security_groups                      | default                                       |
    | status                               | BUILD                                         |
    | tenant_id                            | eef39c42d1ae4853b07755c1143bf0c6              |
    | updated                              | 2015-12-27T12:57:33Z                          |
    | user_id                              | c6a2e48c7d834623933f161f19711ebb              |
    +--------------------------------------+-----------------------------------------------+
    查看创建的虚拟机状态
    [root@linux-node1 ~]# nova list
    +--------------------------------------+----------------+--------+------------+-------------+---------------------+
    | ID                                   | Name           | Status | Task State | Power State | Networks            |
    +--------------------------------------+----------------+--------+------------+-------------+---------------------+
    | 0723632f-18a0-4f61-9dd0-17e1aa97920d | hello-instance | ACTIVE | -          | Running     | flat=192.168.56.101 |
    +--------------------------------------+----------------+--------+------------+-------------+---------------------+


    [root@linux-node1 ~]# ssh cirros@192.168.56.101
    The authenticity of host '192.168.56.101 (192.168.56.101)' can't be established.
    RSA key fingerprint is a9:52:a9:7b:fb:9b:c9:bb:a7:08:92:01:f7:5d:d8:cc.
    Are you sure you want to continue connecting (yes/no)? ye
    Please type 'yes' or 'no': yes
    Warning: Permanently added '192.168.56.101' (RSA) to the list of known hosts.
    $ whoami
    cirros
    已创建成功并且可以登录了


    用命令获取虚拟机的url地址
    [root@linux-node1 ~]# nova get-vnc-console hello-instance novnc
    +-------+------------------------------------------------------------------------------------+
    | Type  | Url                                                                                |
    +-------+------------------------------------------------------------------------------------+
    | novnc | http://192.168.56.11:6080/vnc_auto.html?token=a3e0cf13-5232-41f4-a1a5-5598b2479114 |
    +-------+------------------------------------------------------------------------------------+
    在浏览器中输入 http://192.168.56.11:6080/vnc_auto.html?token=a3e0cf13-5232-41f4-a1a5-5598b2479114
    则可以登录到虚拟机


    ###############################################################################################################################
    [root@linux-node1 ~]# grep -n '^[A-Z]' /etc/openstack-dashboard/local_settings 
    9:DEBUG = False
    10:TEMPLATE_DEBUG = DEBUG
    15:WEBROOT = '/dashboard/'
    29:ALLOWED_HOSTS = ['*',]
    92:LOCAL_PATH = '/tmp'
    103:SECRET_KEY='3f29f265e53c94596fdf'
    108:CACHES = {
    115:CACHES = {
    122:EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
    138:OPENSTACK_HOST = "192.168.56.11"
    139:OPENSTACK_KEYSTONE_URL = "http://%s:5000/v2.0" % OPENSTACK_HOST
    140:OPENSTACK_KEYSTONE_DEFAULT_ROLE = "user"
    170:OPENSTACK_KEYSTONE_BACKEND = {
    201:OPENSTACK_HYPERVISOR_FEATURES = {
    209:OPENSTACK_CINDER_FEATURES = {
    216:OPENSTACK_NEUTRON_NETWORK = {
    280:IMAGE_CUSTOM_PROPERTY_TITLES = {
    292:IMAGE_RESERVED_CUSTOM_PROPERTIES = []
    309:API_RESULT_LIMIT = 1000
    310:API_RESULT_PAGE_SIZE = 20
    313:SWIFT_FILE_TRANSFER_CHUNK_SIZE = 512 * 1024
    316:DROPDOWN_MAX_ITEMS = 30
    320:TIME_ZONE = "Asia/Shanghai"
    363:POLICY_FILES_PATH = '/etc/openstack-dashboard'
    364:POLICY_FILES_PATH = '/etc/openstack-dashboard'
    387:LOGGING = {
    499:SECURITY_GROUP_RULES = {
    650:REST_API_REQUIRED_SETTINGS = ['OPENSTACK_HYPERVISOR_FEATURES']
    [root@linux-node1 ~]# systemctl restart httpd


    http://192.168.56.11/dashboard/

























    展开全文
  • 步进电机 MIDI 音乐 MATLAB+STM32

    千次阅读 2018-01-01 16:53:02
     整个制作周期耗费将近一天,分为两块:1.MIDI音乐格式的编码及提取;2.Stm32控制步进电机的演奏。 首先要解决MIDI音乐文件的读取,变成我能理解的格式。在这里我采用MATLAB进行读取,从其帮助文件中找到了一个叫...
  • 接上篇讲,当顺利捕获了某一时刻的MidiMessage之后,我们该怎样对捕获的信息进行处理呢,我们又怎么知道当前产生的这个... // 获取MIDI数据长度 byte[] data = msg.getMessage(); // 获取MIDI信息所包含的数据 in
  • VCV手册 Markdown 源仓库 贡献 此仓库就像Wiki,但是您必须发送质量请求请求才能获得直接的请求访问权限。 分叉此仓库,进行质量改进,然后提出拉动请求。 如果我接受,我将把您添加为回购维护者,这样您就可以直接...
  • 该MP3设计根据功能主要分为四个模块:核心板是 mega64(ATmega64数据手册)、CH375 接口板、VS1003(VS1003数据手册)模块、Nokia5110 液晶模块。 具体介绍: 该MP3核心板是 mega64 的开发板模式,所有IO 均用上了, ...
  • VS1003中文数据手册

    2012-06-25 20:11:19
    VS1003 是由芬兰VLSI 公司出品的一款单芯片的MP3/WMA/MIDI 音频解码和ADPCM 编码芯片,其拥有一个高 性能低功耗的DSP 处理器核VS_DSP,5K 的指令RAM,0.5K 的数据RAM,串行的控制和数据输入接口,4 个通 用IO 口,一...
  • MusE是MIDI /音频音序器,具有录音和编辑功能,最初由Werner Schweer编写,现在由MusE开发团队开发和维护。 MusE的目标是成为一个完整Linux多轨虚拟工作室。 它是根据GNU通用公共许可证发布的。 访问MusE网站: ://...
  • VS1053音频手册

    2018-10-31 00:00:10
    音频解码芯片,VS1053b 是单片Ogg Vorbis/MP3/AAC/WMA/MIDI音频解码器,及IMA ADPCM 编码器和用户加载的Ogg Vorbis编码器。它包含了一个高性能、有专利的低功耗DSP 处理器内核VS_DSP4、工作数据存储器、供用户应用...
  • VS1003B是一个多功能的MP3和WMA解码芯片,支持多种音频格式解码,包括:MP3、MP3+V、WMA、WAV、MIDI、SP-MIDI。 VS1003B具有以下的技术特性:单独的模拟、数字和IO供电电源;串行的数据和控制接口(SPI);具有内部...
  • vs1003的使用手册

    2011-03-23 14:44:33
    VS1003的手册 VS1003 is a single-chip MP3/WMA/MIDI audio decoder and ADPCM encoder. It contains a highperformance, proprietary low-power DSP processor core VS DSP4, working data memory, 5 KiB ...
  • vs1053b芯片手册

    2012-09-05 09:59:13
    Ogg Vorbis/MP3/AAC/WMA/FLAC/ MIDI AUDIO CODEC CIRCUIT
  • VS1053中文手册 Ogg Vorbis 解码;MPEG 1 & 2 音频阶层III (CBR +VBR +ABR);阶层 I 和 II 可选;MPEG4/2 AAC‐LC(+PNS),HE‐AAC V2 (级别3) (SBR + PS);WMA 4.0/4.1/7/8/9 所有特性注1 (profiles)(5‐384kbps)...
  • D3 Arduino上的软串口的TX引脚(D3引脚)连接音效板上的MIDI引脚 D4 : Arduino上的D4引脚连接音效板上的RESET引脚 */ //软串口库 #include &amp;amp;lt;SoftwareSerial.h&amp;amp;gt; Softwar...
  • grandMA 2 中文手册.pdf

    2019-07-24 15:08:48
    中文MA2完全手册,适合MA控台各种细节功能的学习和查阅
  • 语音播报芯片20190228-SC5XB_V3.35使用手册。SC5XB 系列是最新推出多功能单芯片4 位CMOS 控制器语音芯片,提供4 通道的语音/Midi 合成功能,语音合成方式采用先进的高音质ADPCM 算法,最高采样率可达CD 音质44.1kHz...
  • esp8266 技术参考手册

    2017-09-05 10:12:00
    没有0分的选项,选择了1分下载。 这个是esp8266的技术参考手册,英文的,官网也有,如果懒的去官网下载或者找不到,就到这里下载吧 esp8266-technical_reference_en.pdf
  • VS1053B中文手册

    2011-04-29 14:17:25
    VS1053 是目前 VLSI 公司VS10xx系列最强悍的芯片了,除了能播放各种音乐格式,还支持 OGG 实时编码录音。 VS1053特性: 1、Ogg Vorbis 解码; MPEG 1 & 2 音频阶层III (CBR ... 通用 MIDI 1 / SP‐MIDI 格式0的文件;

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,044
精华内容 417
关键字:

midi手册