MIDI信息隐藏(MATLAB,信息隐藏与数字水印实验)
一、MIDI简介
MIDI(Musical Instrument Digital Interface,乐器数字接口),电子乐器制造商们建立的通信标准,辅助音乐创作、确定电脑音乐程序,用音符的数字控制信号来记录音乐。
一个标准MIDI文件基本上由两部分组成:头块和音轨块。
头块用来描述整个MIDI文件基本信息。
音轨块则包含一系列由MIDI消息构成的MIDI数据流。原则上,可为某种声音、某种乐谱或某种乐器等分配一个音轨块。
MIDI文件中前四个字节是ASCI1字符"MThd" ,用来判断该文件是否为Midi文件,而随后的四个字节指明文件头描述部分的字节数,它总是6,所以一定是"00 00 00 06"。
随后的ff ff nn nn dd dd中的nn nn表示指定轨道数,也就是实际音轨数加上一个全局音轨。
头块之后剩下的文件部分是一个或多个音轨块,每一个音轨块格式见下表。
每一个MIDI事件的构成:
MIDI事件= <delta time> <MIDI消息>
< delta time>采用可变长编码,它决定了其后的MIDI消息被执行的时间。一个MIDI 消息由一个状态字节及多个数据字节构成。MIDI消息根据性质可分为通道消息 (Channel Message)和系统消息(System Message)两大类。
通道消息对单一的MIDI Channel起作用,其Channel是利用状态字节的低4位来表示,可从0~15共有16个Channel。通道消息又分为声音消息和模式消息。声音消息用于控制合成器的声音产生。模式消息则为最多达16条通道分配声音关系,包括设定单音模式或复音模式等。
MIDI文件的声音消息有7种,见下表。
改变MIDI音乐文件的部分声音消息并不影响MIDI文件的听觉效果,通过实验,
改变 声音开启 的最低位比特、乐器编号 的最低位比特和 通道触动压力 的低4比特位,
都不会引起听觉差异,因此可在这三种声音消息中嵌入水印信息。
若(s[i]&0xf0) =0x90,十六进制90转十进制为144,转二进制为1001 0000
则在第i+2个字节s[i+2]中嵌入1比特水印信息,表示修改声音开启的最低位。
若(s[i]&0xf0) =0xc0,c0=192=1100 0000
则在第i+1个字节s[i+1]中嵌入1比特水印信息,表示修改乐器编号的最低位比特。
若(s[i]&0xf0) =0xd0,d0=208=1101 0000=16+64+128
则在第i+1个字节s[i+1]中嵌入4比特水印信息,表示修改通道触动压力的低4比特位。
二、MIDI隐藏代码
目的:在a.txt中写入“123456789”藏入love.mid后得到midihide.mid
clear;
clc;
hidefid=fopen('a.txt','r');
[msg,count]=fread(hidefid,inf,'ubit1');
fid=fopen('love.mid','r');
[wa,length]=fread(fid,inf,'uint8');
fclose(hidefid);
fclose(fid);
modcount=1;
p=1;
for i=1:length
if bitand(wa(i,1),240)==144&&p<=count % 240=1111 0000 144=1001 0000
wa(i+2,1)=bitset(wa(i+2,1),1,msg(p,1)); % msg(行,列)
p=p+1;
i=i+3;
modcount=modcount+1;
elseif bitand(wa(i,1),240)==192&&p<=count % 1100 0000
wa(i+1,1)=bitset(wa(i+1,1),1,msg(p,1));
p=p+1;
i=i+2;
modcount=modcount+1;
elseif bitand(wa(i,1),240)==208&&p<=count-3 % 必须足够4位才可以隐藏
wa(i+1,1)=bitset(wa(i+1,1),1,msg(p,1));
wa(i+1,1)=bitset(wa(i+1,1),2,msg(p+1,1));
wa(i+1,1)=bitset(wa(i+1,1),3,msg(p+2,1));
wa(i+1,1)=bitset(wa(i+1,1),4,msg(p+3,1));
p=p+4;
i=i+2;
modcount=modcount+1;
else
i=i+1;
end
end
fid=fopen('midihide.mid','a');
fwrite(fid,wa);
fclose(fid);
三、MIDI提取代码
clear;
clc;
fid=fopen('midihide.mid','r');
[wa,length]=fread(fid,inf,'uint8');
getfid=fopen('midget.txt','a');
fclose(fid);
count=72; % 这个值的选择依据隐藏的数据,如果是9位数字或字母就是9×8=72,如果是2个汉字就是2×16=32
p=1;
for i=1:length
if(bitand(wa(i,1),240)==144)&&(p<=count)
fwrite(getfid,bitget(wa(i+2,1),1),'ubit1');
i=i+3;
if p==count
break;
end
p=p+1;
elseif(bitand(wa(i,1),240)==192)&&(p<=count)
fwrite(getfid,bitget(wa(i+1,1),1),'ubit1');
i=i+2;
if p==count
break;
end
p=p+1;
elseif(bitand(wa(i,1),240)==208)&&(p<=count-3)
fwrite(getfid,bitget(wa(i+1,1),1),'ubit1');
fwrite(getfid,bitget(wa(i+1,1),2),'ubit1');
fwrite(getfid,bitget(wa(i+1,1),3),'ubit1');
fwrite(getfid,bitget(wa(i+1,1),4),'ubit1');
i=i+2;
if p==count
break;
end
p=p+4;
end
end
fclose(getfid);
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)