【问题标题】:expand/fill-in a Matlab matrix展开/填充 Matlab 矩阵
【发布时间】:2011-07-23 23:34:39
【问题描述】:

我是 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,则不复制/不执行任何操作。

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

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

那么谁能告诉我该怎么做?我在这里用头撞砖墙!

【问题讨论】:

    标签: matlab vector matrix midi


    【解决方案1】:

    即使列表的顺序完全随机,这里也有一个可行的解决方案。它基于以下思想:向量[0 1 0 0 -1 0 0]的累积和为[0 1 1 1 0 0 0]。这对应于时间 2 的“on”和时间 5 的“off”。现在我们需要做的就是用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)
    

    【讨论】:

    • 非常有趣,谢谢!但是我如何将结果视为一个新矩阵,以便我可以检查它?我的实际 MIDI 文件的输出可视化显示它太大(有 88000 行)。
    • 换句话说,有没有办法将此输出视为 excel 文件?另外,从我在 matlab 输出中可以看出,我有时会得到 -2 或 -1 作为结果?我不确定这意味着什么。
    • @Tom:output 可能包含负值的唯一原因是(1)有一个没有开始的停止,或者(2)开始和停止有重复的值 - 请参阅我的编辑如何修复#2。此外,要写入 Excel,请使用 xlswrite('myFile.xls',output)
    • 我还注意到其他一些奇怪的事情——这是数据的错误。当一个音符重复时,MIDI 文件显示当时的音符为 0,然后在同一时间显示为 1,几行后显示相同的音符。我认为这使脚本感到困惑。在预览中,您似乎已经预料到了这个问题!脚本的哪一点被改变了?
    • @Tom:是的,这是代码的问题。但是,在分配“on”之前分配“off”应该可以解决问题(我不会在代码中解决这个问题,因为我不想重新输入所有 cmets)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-28
    • 2015-05-15
    • 1970-01-01
    相关资源
    最近更新 更多