我是MATLAB的初学者,在分配作业时面临很多问题。作业的目的是创造具有教授给我们的功能的音乐。我设法创建了一个非常简单的旋律,但我想解决更复杂的问题:我用MIDI写了一个简单的旋律,用文本编辑器将其打开,现在我有了音符的MIDI代码矩阵。
现在,第一步是将这些MIDI代码转换为频率:
我知道freq = 440*power(2, (midicode-69)/12)
。我想创建一个包含通过此公式传递的MIDI代码的矢量/矩阵(从而获得一个包含频率的矩阵),而我似乎找不到解决方法。老师的教材几乎不存在,我的互联网搜索让我更加困惑。
下一步(也是最后一步?)是将这些代码传递到教师功能中。它称为newsound(f)
,并以频率f
作为参数。然后,它通过将频率分量和其他实用程序一一相加来创建声音。
现在,我需要传递给MATLAB soundsc()
函数的是newsound(f)
矩阵S
中所有各个频率的结果。
这就是我的意思,最让我感到困惑(我在数学上也不是那么出色,是的...)
假设f(i)
是包含从MIDI转换的频率的矢量/矩阵。然后,S
是1xn
大小的矩阵,1是列,n
是频率量:S = (S1, S2, ..., Sn)
表示S1 = newsound(f(1))
,..., Sn = newsound(f(n))
。
我非常感谢您提供围绕这些矩阵进行游戏的帮助!
答案 0 :(得分:2)
据我了解,每个“声音”可能有多个MIDI代码,每个“声音”中的MIDI代码的数量可能会有所不同。因此,包含您的“声音”的MIDI代码的文本文件midicodes.txt
可能看起来像这样:
60 61 69
62 64
63 68 69 72
第一步是读取该文件的所有内容:
% Read MIDI codes from text file, get cell array of vectors with MIDI codes
fid = fopen('midicodes.txt');
midi_codes = textscan(fid, '%s', 'delimiter', '\n')
midi_codes = cellfun(@(line) str2num(line), midi_codes{1}, 'UniformOutput', false)
fclose(fid);
textscan
将把整个行作为文本文件中的字符串(或更好的字符集)提供给我们(由于MIDI代码向量的长度不同,我们在这里需要cell arrays):
midi_codes =
{
[1,1] =
{
[1,1] = 60 61 69
[2,1] = 62 64
[3,1] = 63 68 69 72
}
}
然后,我们使用str2num
将每个字符串(或更好的是:字符数组)行转换为数字向量。为了对单元格数组中的每个单元格执行此操作,我们使用cellfun
方法。
midi_codes =
{
[1,1] =
60 61 69
[2,1] =
62 64
[3,1] =
63 68 69 72
}
现在,我们为频率计算设置一个anonymous function,并计算所有MIDI代码的频率:
% Anonymous function to convert (vectors of) MIDI codes to frequencies
freq = @(midicode) 440 * 2.^((midicode - 69) / 12);
% Calculate frequencies for all MIDI codes
frequencies = cellfun(freq, midi_codes, 'UniformOutput', false)
输出:
frequencies =
{
[1,1] =
261.63 277.18 440.00
[2,1] =
293.66 329.63
[3,1] =
311.13 415.30 440.00 523.25
}
现在,我们假设newsound
函数实际上是根据频率矢量计算一些“声音”的。作为一个模型,我创建了这个newsound.m
函数文件:
function out = newsound(freq)
out = sum(sin(freq));
end
我们可以为每个MIDI代码/频率矢量创建实际的“声音”:
% Generate sounds for all frequencies
sounds = cellfun(@newsound, frequencies, 'UniformOutput', true)
输出:
sounds =
0.070850
-0.759869
1.628095
现在:
% Play sounds!?
soundsc(sounds);
如果文本文件的外观不同,例如,如果使用其他定界符,则需要调整输入阅读部分。如果所有MIDI代码向量的长度都相同,则还可以使用纯数字数组而不是单元格数组。
希望有帮助!
免责声明:已在Octave 5.1.0中进行了测试,但语法应与MATLAB完全兼容。如果没有,请报告任何错误,我将尝试尽快解决。
编辑:根据评论的要求,以下是完整脚本:
% Read MIDI codes from text file, get cell array of vectors with MIDI codes
fid = fopen('midicodes.txt');
midi_codes = textscan(fid, '%s', 'delimiter', '\n')
midi_codes = cellfun(@(line) str2num(line), midi_codes{1}, 'UniformOutput', false)
fclose(fid);
% Anonymous function to convert (vectors of) MIDI codes to frequencies
freq = @(midicode) 440 * 2.^((midicode - 69) / 12);
% Calculate frequencies for all MIDI codes
frequencies = cellfun(freq, midi_codes, 'UniformOutput', false)
% Generate sounds for all frequencies
sounds = cellfun(@newsound, frequencies, 'UniformOutput', true)
% Play sounds!?
%soundsc(sounds);