不是很懂,粗浅理解。有误请指出
function w = lrcnmat2snd(nmat,synthtype,fs)
%nmat 每行: 启始(拍数) 、 间隔(拍数)、声道、音高(dB)、速率、起始(时间sec)、间隔(时间sec)
% Create waveform of NMAT using a simple
% synthesisc通过midi文件格式nmat矩阵简单合成波形文件wav
% w = nmat2snd(nmat,<synthtype>,<fs>,<f_min>,<f_max>)
%波形数据=w';nmat输入矩阵,合成类型,采样频率
% Create waveform of NMAT using a simple FM synthesis. The default sampling rate is
% 22050 Hz and velocities are scaled to have默认采样频率22050Hz,速率最大为1
% a max value of 1.
%
% SYNTHTYPE 'fm' (default) uses FM synthesis to approximate horn
% sound.默认fm合成
% SYNTHTYPE 'shepard' creates waveform of NMAT using Shepard tones.
%使用shepard创建波形
% These tones have also been
% called 'Circular tones' because they are specifically constructed to contain
% frequency components at octave intervals with an emphasis of the spectral
% components between 500Hz and 1000 Hz that effectively
% eliminates octave information (Shepard, 1964).
%圆形音调,构造八度音程内的频率分量。重点为500-1000Hz的频谱成分
%
% Part of the code has been obtained from the work of Ed Doering.
% Ed.Doering@Rose-Hulman.Edu
%
% Input argument:
% NMAT = notematrix矩阵
% SYNTHTYPE (Optional) = Synthesis type, either FM synthesis ('fm', default)
% or Shepard tones ('shepard')两个选择'fm'或者'shepard'
% FS (optional) = sampling rate (default 22050)采样频率设置
%
% Output:
% Y = waveform返回波形数据,行存放
%
% Example 1: samples1 = nmat2snd(laksin);
% Example 2: samples2 = nmat2snd(laksin,'shepard', 22050);
%
% Reference:
% Moore, F. R. (1990). Elements of Computer Music. New York: Prentice-Hall.
% Shepard, R. N. (1964). Circularity in judgements of
% relative pitch. Journal of the Acoustical Society of America,
% 36, 2346-2353.
%
% Change History :
% Date Time Prog Note
% 29.9.2003 20:13 TE Created under MATLAB 5.3 (PC)
% 4/15/05 JBP added ability to specify number of partials in
% tone, also shifted harmonic envelope such that tones are actually 3
% semitones lower than desired. To fix, transpose input up by 3 semitones
% (3 midi notes) to get correct pitch with better envelope.
% 2.5.2005 9:30 TE Almost a total revision if the shepard function
%�Part of the MIDI Toolbox, Copyright �2004, University of Jyvaskyla, Finland
% See License.txt
if isempty(nmat), return; end%如果没有待转换数据结束
if nargin<3, fs = 22050; end%如果没有设置采样频率,启动默认设置22050hz
if nargin<2, synthtype='fm'; end%如果没有设置合成方式,启动默认设置
%%%%%%%%%%%% WARNINGS
sample_in_K = (fs*(1+nmat(end,6) + nmat(end,7)))/1024;
%从开始到目前的采样点数/1024(采样频率*开始播放到播完这行的时间/1024)
if sample_in_K<1000
disp([num2str(sample_in_K,4) 'K samples']);
elseif sample_in_K>1000
%TODO: this needs to be revised需要修正
f=1;
while f==1%用于选择是否合成
i = input([num2str(sample_in_K,4),'Ks of samples, synthesis may last for an extended period of time. \nDo you wish to continue? Y/N [Y]: '],'s');
if isempty(i)
i = 'Y';%输入字符空,默认继续合成
f=2;%结束判断是否合成
end
switch lower(i)
case 'y'%继续合成
f=2;%结束判断是否合成
case 'n'
disp('synthesis cancelled')%取消合成
y=[]; f=2; return%程序结束返回
otherwise
disp([i,' is not a valid choice'])%无效输入
y=[]; %清空
f=1;%继续判断是否合成输入
end
end
end
% END WARNINGS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
switch lower(synthtype)
case 'fm'%fm合成
% convert MIDI numbers to frequencies in Hz把nmat中数据转换成频率
%notes 每行:开始时间nmat(:,6)(sec) 、时间间隔nmat(:,7)+0.01、频率(根据nmat(:,4)音高转换)、速率nmat(:,5)
notes(:,1)=onset(nmat,'sec');%起始时间
notes(:,2)=dur(nmat,'sec')+0.01;%时间间隔
notes(:,3)=midi2hz(pitch(nmat));%音高获得的基频
notes(:,4)=velocity(nmat);%速率
% generate time vector for output waveform; end time is nearest integer
% above the last note event time (give some extra room)
%时间轴设置:时间轴间隔1/采样频率,只入不舍(最大的起始时间+最大的时间间隔减一轴时间轴间隔)
tt=0:1/fs:ceil(max(notes(:,1))+max(notes(:,2)))-(1/fs);%ceil取整数,只入不舍
% scale note velocities so max velocity is one速率调整为占最大速率的比例
notes(:,4)=notes(:,4)/max(notes(:,4));
% convert each note to a waveform, and add the waveform to the output waveform
y=zeros(size(tt));%设置波形缓冲区大小
for i=1:size(notes,1),
% convert note to waveform using the instrument defined by 'fncname'
w=feval('fmsynth',notes(i,2:4),fs); % 一个音符波形=函数feval根据时间间隔、频率、调整后速率、采样频率
% place waveform in the output file
ttint=round(notes(i,1)*fs)+1:round(notes(i,1)*fs)+length(w);%音符波形存放下标序列=(四舍五入(起始时间):四舍五入(起始时间+音符波形数据))
y(ttint)=y(ttint)+w;%这个音符波形存放进原来的后面
end
w=y/4; %rescale to fit between -1 and +1 (4 is a conservative estimate)
% play the sound if no output arguments, otherwise return the sound
%if nargout<1
% soundsc(y,fs);
%else
% out=y;
%end
case 'shepard'%shepard合成
notes = size(nmat,1);%音符个数
duration =dur(nmat,'sec');%时间间隔
pitchheight =pitch(nmat);%音高
onsets=onset(nmat,'sec');%起始时间
% create vector for output waveform
tt=0:1/fs:ceil(max(onset(nmat,'sec'))+max(dur(nmat,'sec')+.01))-(1/fs);
% convert each note to a waveform, and add the waveform to the output waveform
y=zeros(size(tt));
for i=1:notes
w=feval('shepardtone',pitchheight(i),duration(i),fs);%音高,时间间隔,采样频率
% place waveform in the output file
ttint=round(onsets(i)*fs)+1:round(onsets(i)*fs)+length(w);
y(ttint)=y(ttint)+w;
end
w=y/30; %rescale to fit between -1 and +1 (30 is a conservative estimate)
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function y1=fmsynth(note,fs)
% FM horn instrument (Moore p. 327)
%最基本的FMinstrument包括两个正弦曲线振荡器,
%一个是稳定不变的载波频率fc(CarrierFrequnecy)振荡器;
%一个是调制频率fm(ModulationFrequency)振荡器
%单个音符的【时间间隔、频率、调整后速率】【采样频率】
% note is in duration-frequency-amplitude format
% (duration in seconds, frequency in Hz, amplitude usually between 0 and 1)
%根据 间隔秒、频率Hz、振幅0~1三个参数
% generate time vector生成时间向量
du=note(1);%取这个音符的时间间隔
tt=0:1/fs:du;
fc = note(2); %carrier frequency取这个音符的频率
h = 1; %harmonicity ratio调和比率
fm = h*fc; %modulating frequency调制频率
Imin=0; %minimum modulation index最小的调制指数
Imaxmin = 5; %modulation index (max value above Imin)调制指数(最大值高于Imin)
% envelopes包络
%[0 0 -1;
% 0.2 1 -1;
% 0.3 0.708 0;
%0.8 0.631 -1;
%1 0 0]最后一行数据用于对齐参数
%开始到结束的采样点时间比例
%幅值
%单调/不单调?
env=envelope([0 0 -1; 0.2 1 -1; 0.3 0.708 0; 0.8 .631 -1; 1 0 0],du,fs);
%disp(['env ' num2str(size(env)) 'tt ' num2str(size(tt))])
aa = note(3)*env; %载波振幅
ii = Imin+Imaxmin*env;%调制振幅
% output waveform
y1 = aa.*sin(2*pi*fc*tt + ii.*sin(2*pi*fm*tt));
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function y2=envelope(v,du,fs)
%矩阵(这个矩阵什么意思不懂),一个音符的时间间隔序列秒,采样频率hz
% envelope function (Moore p. 184, and p. 514)
% env=envelope(vlist,du,fs) accepts a matrix 'vlist' where each row is a triple indicating
% time (arbitrary units), value (usually between 0 and 1), and transition type.
% 'du' is the envelope duration in seconds, and 'fs' is the sampling frequency in Hz.
%
% See p. 184 and p. 514 of F. Richard Moore's text ("Elements of Computer Music", 1990,
% Find the number of vertices
numv=size(v,1);%行数
% Set the time column to occur over duration
v(:,1)=(v(:,1)/v(numv,1))*du;%设置时间
% Generate the envelope (guard against divide by zero error by adding
% a small number to denominator)防止除以0生成包络。
y2=[];
for k=1:numv-1
ii=linspace(0,1,(v(k+1,1)-v(k,1))*fs);%k到k+1这段时间内,第i个点的采样比序列。i/这段时间采样点数
if v(k,3)==0
y2=[y2 linspace(v(k,2),v(k+1,2),size(ii,2))];%如果是单调,生成等间隔波加入原来
else
y2=[y2 v(k,2)+(v(k+1,2)-v(k,2))*(1-exp(v(k,3)*ii))/(1-exp(v(k,3)+1e-12))];
%y2=[y2 当前振幅+后前振幅差*(1-e^(k*比例)/(1-e^(k*1)))] ;1e-12防止分母出现零 这个公式我没弄懂?假装懂
end
end
% Figure out how many samples are expected指出需要多少样本点
nums=size(0:1/fs:du,2);
% Figure out how many samples were generated指出多少个样本点生成
numg=size(y2,2);
% Pad or trim the vector as needed
% (NOTE: This method is a bit of a kluge -- maybe someone can suggest a better
% way!)样本点过多删除或者不够补零
if numg<nums
y2=[y2 zeros(1,nums-numg)];
elseif numg>nums
y2(nums+1:numg)=[];
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function s = shepardtone(pitch,dur,fs)
%一个音符:音高 间隔 采样频率
t = 0:1/fs:dur;%一个音符的时间
f = midi2hz(pitch);%由这个音符音高获得频率
u = zeros(size(t));%初始化点数
% Thresholds for the spectra, Krumhansl & Kessler, 1982, p341: "loudness envelope over five-octave range (
% from 77.8 Hz to 2349 Hz), which consisted of three parts: a gradually increasing section over the
% first octave and a half, a constant section over the
% middle two octaves, and a symmetrically decreasing
% section over the last octave and a half. The
% corresponding amplitude of the sine wave components
% at each frequency was determined using the
% amplitude-loudness curves of Fletcher and Munson
% (1933), originally introduced by Shepard (1964).
% Loudness envelope min and max (simpler version than suggested above)响度包络最小和最大
f_min=16;
f_max=20000;
% Number of partials needed
f_max_part = min(f_max,fs/2);%基频最大小于采样周期的一半,各种文献说的
pl=ceil(log2(f_min/f));%只舍不入
ph=floor(log2(f_max_part/f));%四舍五入
partials = f*2.^(pl:ph);%个数ph-pl+1个
% Amplitudes
ampl = 1-cos(2*pi*(log(partials/f_min)./log((f_max)/f_min)));
ampl = ampl/(max(ampl));
% Calculate waves for the partials
warning off
for j=1:length(partials)
u = u + ampl(j).*sin(2*pi*partials(j)*t);%估计随时间的幅度序列
end
% Envelope
ramp=.1;%0.1
envelope(1:ramp*fs)=t(1:ramp*fs).*t(1:ramp*fs);%设置一秒采样频率的前十分一时间轴的平方
envelope(length(t)-ramp*fs+1:length(t))=fliplr(envelope(1:ramp*fs));%设置一秒采样频率的后十分一
envelope(ramp*fs:end-ramp*fs)=max(envelope);%中间设置十分之八设置为包络最大
factor=exp(1)/max(envelope);%一个系数因子
y=envelope.*factor;%包络幅度*系数因子 使得范围在0~e
s=y.*u;%包络幅度*随时间的幅度
warning on