Labfans是一个针对大学生、工程师和科研工作者的技术社区。 论坛首页 | 联系我们(Contact Us)
MATLAB爱好者论坛-LabFans.com
返回   MATLAB爱好者论坛-LabFans.com > 其它 > 资料存档
资料存档 资料存档
回复
 
主题工具 显示模式
旧 2019-12-14, 20:46   #1
poster
高级会员
 
注册日期: 2019-11-21
帖子: 3,006
声望力: 66
poster 正向着好的方向发展
帖子 扩展/填充Matlab矩阵

我在Matlab上还很新,所以需要一个小步骤的解释。

我有一些看起来像这样的MIDI数据:

开/关时间
10 1 61
90 0 61
90 1 72
92 1 87
100 0 72

我想做的是扩大或“填补”空白,以便每时每刻都有一行,并且我有几列显示哪些音符在打开(通常同时有多个音符) )。

最终目标是对给定时间(谐波失谐)上音符之间的整体关系进行一些计算。

所以我在想,也许我需要为每个可能的音符(有127个)创建一个新列,然后每次都为1或0。或者,也许我可以有一个矩阵,它告诉我哪些音符在上面(所以列数各不相同)。

我编写了自己的伪代码,但不知道如何实现它。我怀疑有一个简单的功能可以做到这一点。这是我的伪代码:

从0开始,在时间0处为新的“注释矩阵”
对于数字:0到n
如果数字与时间列中的数字匹配,请转到该行的开/关列。
如果开/关列中为1,则将注释列中的编号复制到相应行的“注释上矩阵”
如果为0,则不要复制/不执行任何操作。

如果数字与时间列中的数字不匹配
复制上一行(如果没有注释,则可以为空白)。

对于新的“注释矩阵”中的每一行,将数字从低到高排列在不同的列中。

谁能告诉我该怎么办?我在这里撞墙撞头!



回答:

即使列表完全随机,这也是一种解决方案。它基于以下思想:向量[0 1 0 0 -1 0 0]的累加和为[0 1 1 1 0 0 0] 。这对应于时间2中的“打开”和时间5中的“关闭”。现在,我们要做的就是用1和-1填充数组,然后运行CUMSUM将其转换为在每一列中具有一个数组,每当那些声音on 。

我假设有128个音符(0-127),并且您想在最后一刻保持沉默(如果所有音符最终都结束了)。请注意,Matlab从1开始计数,因此时间0对应于行#1。

%# midiData is a n-by-3 array with [time,on/off,note] midiData = [... 10 1 61 90 0 61 90 1 72 92 1 87 100 0 72]; %# do not call unique here, because repeated input rows are relevant %# note values can be from 0 to 127 nNotes = 128; %# nTimepoints: find the highest entry in midiData's time-column %# add 2, because midiData starts counting time at 0 %# and since we want to have one additional timepoint in the end nTimepoints = max(midiData(:,1))+2; %# -- new solution --- %# because the input is a bit messed up, we have to use a more complicated %# solution. We'll use `accumarray`, with which we sum up all the %# entries for on (+1) and off (-1) for each row(time)/column(note) pair. %# after that, we'll apply cumsum %# transform the input, so that 'off' is -1 %# wherever the second col of midiData is 0 %# replace it with -1 midiData(midiData(:,2)==0,2) = -1; %# create output in one step %# for every same coordinate (time,note), sum all the %# on/offs (@sum). Force the output to be %# a nTimepoints-by-nNotes array, and fill in zeros %# where there's no information output = accumarray(midiData(:,[1 3])+1,midiData(:,2),... [nTimepoints,nNotes],@sum,0); %# cumsum, and we're done output = cumsum(output,1); 以前的解决方案,出于完整性考虑:

%# --- old solution --- %# create output array, which we'll first populate with 1 and -1 %# after which we transform it into an on-off array %# rows are timepoints, columns are notes output = zeros(nTimepoints,nNotes); %# find all on's %# onIdx is 1 if the second column of midiData is 1 onIdx = midiData(:,2) == 1; %# convert time,note pairs into linear indices for %# writing into output in one step %# Add 1 to time and note, respectively, so that we start counting at 1 plusOneIdx = sub2ind([nTimepoints,nNotes],midiData(onIdx,1)+1,midiData(onIdx,3)+1); %# write "1" wherever a note turns on output(plusOneIdx) = 1; %# now do the same for -1 offIdx = midiData(:,2) == 0; minusOneIdx = sub2ind([nTimepoints,nNotes],midiData(offIdx,1)+1,midiData(offIdx,3)+1); %# instead of overwrite the value in output, subtract 1 %# so that time/note that are both on and off become zeros output(minusOneIdx) = output(minusOneIdx) - 1; %# run cumsum on the array to transform the +1/-1 into stretches of 1 and 0 %# the 'dim' argument is 1, because we want to sum in the direction in %# which rows are counted output = cumsum(output,1); %# for fun, visualize the result %# there's white whenever a note is on imshow(output)

更多&回答...
poster 当前离线   回复时引用此帖
回复

主题工具
显示模式

发帖规则
不可以发表新主题
不可以发表回复
不可以上传附件
不可以编辑自己的帖子

启用 BB 代码
论坛禁用 表情符号
论坛启用 [IMG] 代码
论坛启用 HTML 代码



所有时间均为北京时间。现在的时间是 03:21


Powered by vBulletin
版权所有 ©2000 - 2025,Jelsoft Enterprises Ltd.