展开/填充 Matlab 矩阵

发布于 2024-10-27 18:27:32 字数 684 浏览 4 评论 0原文

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

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

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

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

I'm pretty new at Matlab so would need a baby-steps explanation.

I have some MIDI data which looks a bit like this:

time on/off note
10 1 61
90 0 61
90 1 72
92 1 87
100 0 72

What I want to do is expand or 'fill-in' the gaps so that I have a row for every single moment in time, and I have columns which show which notes are on (there is often more than one note at the same time).

the ultimate goal is to do some calculations about the overall relationship between notes on (the harmonic dissonance) at a given time.

So I was thinking that maybe I needed a new column for every single possible note (there are 127), and then a 1 or 0 for every time. Or maybe I can just have a matrix which just tells me which notes are on (so the number of columns varies).

I wrote my own pseudo-code, but have no idea how to implement it. I suspect there is a simple function that can do this. Here is my pseudo-code:

start with 0, at time 0 in a new 'notes-on matrix'
for numbers: 0 to n
if the number matches a number in the time column, go to the on/off column for that row.
if 1 in on/off column then copy number in notes column to 'notes-on matrix' for corresponding row
if 0 then don't copy/do nothing.

if number doesn't match number in time column
copy the previous row (which can be blank if there were no notes on).

for each row in the new 'notes-on matrix', arrange numbers low to high in different columns.

So can anyone tell me what to do?? I'm banging my head against a brick wall here!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

怕倦 2024-11-03 18:27:32

即使列表的顺序完全随机,这里的解决方案也可以工作。它基于以下思想:向量[0 1 0 0 -1 0 0]的累积和为[0 1 1 1 0 0 0]。这对应于时间 2 中的“on”,以及时间 5 中的“off”。现在我们需要做的就是用 1-1 填充一个数组,然后运行CUMSUM 将其转换为每列都有 1 的数组每当声音开启时。

我假设有 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)

Here's a solution that will work even if the list is in a completely random order. It is based on the following idea: The cumulative sum of the vector [0 1 0 0 -1 0 0] is [0 1 1 1 0 0 0]. This corresponds to "on" in time 2, and "off" in time 5. Now all we need to do is populate an array with 1 and -1, and run CUMSUM to transform it into an array that has, in each column, ones whenever the sound is on.

I assume that there are 128 notes (0-127), and that you want to have one time step of silence (if all notes eventually end) at the very end. Note that Matlab starts counting at 1, so time 0 corresponds to row #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);

The previous solution, for completeness:

%# --- 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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文