CM0340 Tutorial 5: MATLAB BASIC DSP and Synthesis 1 In this tutorial we explain some of the DSP and MATLAB concepts discussed in the lectures leading up to Digital Audio Synthesis. We start by looking at basic signal waveforms. The code that is used over the next few slides is waveforms.m JJ II J I Back Close Simple Waveforms 2 • Frequency is the number of cycles per second and is measured in Hertz (Hz) • Wavelength is inversely proportional to frequency i.e. Wavelength varies as 1 f requency JJ II J I Back Close The Sine Wave and Sound 3 The general form of the sine wave we shall use (quite a lot of) is as follows: y = A.sin(2π.n.Fw /Fs) where: A is the amplitude of the wave, Fw is the frequency of the wave, Fs is the sample frequency, n is the sample index. JJ II J I MATLAB function: sin() used — works in radians Back Close MATLAB Sine Wave Radian Frequency Period Basic 1 period Simple Sine wave — 1 period is 2π radians 4 % Basic 1 period Simple Sine wave i=0:0.2:2*pi; y = sin(i); figure(1) plot(y); % use stem(y) as alternative plot as in lecture notes to % see sample values title(’Simple 1 Period Sine Wave’); JJ II J I Back Close MATLAB Sine Wave Amplitude Sine Wave Amplitude is -1 to +1. 5 To change amplitude multiply by some gain (amp): % Now Change amplitude amp = 2.0; y = amp*sin(i); figure(2) plot(y); title(’Simple 1 Period Sine Wave Modified Amplitude’); JJ II J I Back Close MATLAB Sine Wave Frequency % % % % % % Natural frequency is 2*pi radians If sample rate is F_s HZ then 1 HZ is 2*pi/F_s If wave frequency is F_w then freequency is F_w* (2*pi/F_s) set n samples steps up to sum duration nsec*F_s where nsec is the duration in seconds So we get y = amp*sin(2*pi*n*F_w/F_s); 6 F_s = 11025; F_w = 440; nsec = 2; dur= nsec*F_s; n = 0:dur; y = amp*sin(2*pi*n*F_w/F_s); figure(3) plot(y(1:500)); title(’N second Duration Sine Wave’); JJ II J I Back Close MATLAB Sine Wave Plot of n cycles % To plot n cycles of a waveform 7 ncyc = 2; n=0:floor(ncyc*F_s/F_w); y = amp*sin(2*pi*n*F_w/F_s); figure(4) plot(y); title(’N Cycle Duration Sine Wave’); JJ II J I Back Close Cosine, Square and Sawtooth Waveforms MATLAB functions cos() (cosine), square() and sawtooth() similar. 8 JJ II J I Back Close MATLAB Cos v Sin Wave % Cosine is same as Sine (except 90 degrees out of phase) yc = amp*cos(2*pi*n*F_w/F_s); figure(5); hold on plot(yc,’b’); plot(y,’r’); title(’Cos (Blue)/Sin (Red) Plot (Note Phase Difference)’); hold off; 9 JJ II J I Back Close Relationship Between Amplitude, Frequency and Phase 10 JJ II J I Back Close Amplitudes of a Sine Wave % Simple Sin Amplitude Demo samp_freq = 400; dur = 800; % 2 seconds amp = 1; phase = 0; freq = 1; s1 = mysin(amp,freq,phase,dur,samp_freq); 11 axisx = (1:dur)*360/samp_freq; % x axis in degrees plot(axisx,s1); set(gca,’XTick’,[0:90:axisx(end)]); fprintf(’Initial Wave: \t Amplitude = ...\n’, amp, freq, phase,...); % change amplitude amp = input(’\nEnter Ampltude:\n\n’); s2 = mysin(amp,freq,phase,dur,samp_freq); hold on; plot(axisx, s2,’r’); set(gca,’XTick’,[0:90:axisx(end)]); The code is sinampdemo.m JJ II J I Back Close mysin MATLAB code The above call function mysin.m which a simple modified version of previous MATLAB sin function to account for phase. function s = mysin(amp,freq,phase,dur, samp_freq) % example function to so show how amplitude,frequency and phase % are changed in a sin function % Inputs: amp - amplitude of the wave % freq - frequency of the wave % phase - phase of the wave in degree % dur - duration in number of samples % samp_freq - sample frequncy 12 x = 0:dur-1; phase = phase*pi/180; s = amp*sin( 2*pi*x*freq/samp_freq + phase); JJ II J I Back Close Amplitudes of a Sine Wave: sinampdemo output 1 13 0.8 0.6 0.4 0.2 0 −0.2 −0.4 −0.6 −0.8 −1 0 90 180 270 360 450 540 630 720 JJ II J I Back Close Frequencies of a Sine Wave % Simple Sin Frequency Demo samp_freq = 400; dur = 800; % 2 seconds amp = 1; phase = 0; freq = 1; s1 = mysin(amp,freq,phase,dur,samp_freq); 14 axisx = (1:dur)*360/samp_freq; % x axis in degrees plot(axisx,s1); set(gca,’XTick’,[0:90:axisx(end)]); fprintf(’Initial Wave: \t Amplitude = ...\n’, amp, freq, phase,...); % change amplitude freq = input(’\nEnter Frequency:\n\n’); s2 = mysin(amp,freq,phase,dur,samp_freq); hold on; plot(axisx, s2,’r’); set(gca,’XTick’,[0:90:axisx(end)]); The code is sinfreqdemo.m JJ II J I Back Close Amplitudes of a Sine Wave: sinfreqdemo output 1 15 0.8 0.6 0.4 0.2 0 −0.2 −0.4 −0.6 −0.8 −1 0 90 180 270 360 450 540 630 720 JJ II J I Back Close Phases of a Sine Wave % Simple Sin Phase Demo samp_freq = 400; dur = 800; % 2 seconds amp = 1; phase = 0; freq = 1; s1 = mysin(amp,freq,phase,dur,samp_freq); 16 axisx = (1:dur)*360/samp_freq; % x axis in degrees plot(axisx,s1); set(gca,’XTick’,[0:90:axisx(end)]); fprintf(’Initial Wave: \t Amplitude = ...\n’, amp, freq, phase,...); % change amplitude phase = input(’\nEnter Phase:\n\n’); s2 = mysin(amp,freq,phase,dur,samp_freq); hold on; plot(axisx, s2,’r’); set(gca,’XTick’,[0:90:axisx(end)]); The code is sinphasedemo.m JJ II J I Back Close Amplitudes of a Sine Wave: sinphasedemo output 1 17 0.8 0.6 0.4 0.2 0 −0.2 −0.4 −0.6 −0.8 −1 0 90 180 270 360 450 540 630 JJ II J I Back Close MATLAB Square and Sawtooth Waveforms % Square and Sawtooth Waveforms created using Radians ysq = amp*square(2*pi*n*F_w/F_s); ysaw = amp*sawtooth(2*pi*n*F_w/F_s); 18 figure(6); hold on plot(ysq,’b’); plot(ysaw,’r’); title(’Square (Blue)/Sawtooth (Red) Waveform Plots’); hold off; JJ II J I Back Close Triangular Waveform MATLAB function sawtooth(t,width = 0.5) can create a triangular waveform, but its easy to build one ourselves (later we make a smoother sounding sawtooth in similar fashion): % Half Frequency delta = 2*F_w/F_s; % min and max values of simple waveform minf=0;maxf=1; % create triangle wave of centre frequency values figure(7); hold on ytri = []; % plot n cycles while(length(ytri) < floor(ncyc*F_s/F_w) ) ytri = [ ytri amp*(minf:delta:maxf) ]; %upslope doplot = input(’\nPlot Figure? y/[n]:\n\n’, ’s’); if doplot == ’y’, plot(ytri,’r’); figure(7); end lasti = length(ytri); ytri = [ ytri amp*(maxf:-delta:minf) ]; %downslope doplot = input(’\nPlot Figure? y/[n]:\n\n’, ’s’); if doplot == ’y’, plot(ytri,’b’); figure(7); end end title(’Triangular Waveform Plots’); hold off; 19 JJ II J I Back Close Triangular Waveform Display 2 1.8 1.6 20 1.4 1.2 1 0.8 0.6 JJ II J I 0.4 0.2 0 0 5 10 15 20 25 30 35 40 Back Close Using these Waveforms All above waveforms used (as seen in Lecture notes): • Base waveforms for various forms of synthesis: Subtractive, FM, Additive 21 • Modulators and Carrier waveforms for various Digital Audio effects. – Low Frequency Oscillators (LFO) to vary filter cut-off frequencies and delay times JJ II J I Back Close MATLAB filters Matlab filter() function implements an IIR (or an FIR no A components). 22 Type help filter: FILTER One-dimensional digital filter. Y = FILTER(B,A,X) filters the data in vector X with the filter described by vectors A and B to create the filtered data Y. The filter is a "Direct Form II Transposed" implementation of the standard difference equation: a(1)*y(n) = b(1)*x(n) + b(2)*x(n-1) + ... + b(nb+1)*x(n-nb) - a(2)*y(n-1) - ... - a(na+1)*y(n-na) If a(1) is not equal to 1, FILTER normalizes the filter coefficients by a(1). FILTER always operates along the first non-singleton dimension, namely dimension 1 for column vectors and non-trivial matrices, and dimension 2 for row vectors. JJ II J I Back Close A Complete IIR System x(n − 1) x(n) T x(n − 2) x(n − N + 1) T T 23 × × b0 × b1 b2 × × bN −2 bN −1 y(n) + × + × −aM y(n − M ) T + × −aM −1 T + −aM −2 × + −a1 y(n − 1) Here we extend: The input delay line up to N − 1 elements and The output delay line by M elements. T JJ II J I Back Close Complete IIR System Algorithm x(n − 1) x(n) x(n − 2) T × × b0 x(n − N + 1) T T × b1 b2 × × bN −2 bN −1 24 y(n) + × + × −aM y(n − M ) + × −aM −1 T + −aM −2 T × + −a1 y(n − 1) T We can represent the IIR system algorithm by the difference equation: y(n) = − M X k=1 ak y(n − k) + N −1 X k=0 bk x(n − k) JJ II J I Back Close Using filter() in Practice We have two filter banks defined by vectors: A = {ak }, B = {bk }. We have to specify some values for them. • We can do this by hand — we could design our own filters 25 • MATLAB provides standard functions to set up A and B for many common filters. JJ II J I Back Close Using filter() in Practice:Hand Coding Recall from lecture notes: The MATLAB file IIRdemo.m sets up the filter banks as follows: fg=4000; fa=48000; k=tan(pi*fg/fa); 26 b(1)=1/(1+sqrt(2)*k+kˆ2); b(2)=-2/(1+sqrt(2)*k+kˆ2); b(3)=1/(1+sqrt(2)*k+kˆ2); a(1)=1; a(2)=2*(kˆ2-1)/(1+sqrt(2)*k+kˆ2); a(3)=(1-sqrt(2)*k+kˆ2)/(1+sqrt(2)*k+kˆ2); and then applies the difference equation: for n=1:N y(n)=b(1)*x(n) + b(2)*xh1 + b(3)*xh2 - a(2)*yh1 - a(3)*yh2; xh2=xh1;xh1=x(n); yh2=yh1;yh1=y(n); end; JJ II J I Back Close Filtering with IIR: Simple Example Output This produces the following output: 1 x(n) → 0.5 27 0 −0.5 −1 0 2 4 6 8 10 12 14 16 18 n→ 1 y(n) → 0.5 0 −0.5 −1 0 2 4 6 8 10 n→ 12 14 16 18 JJ II J I Back Close Using MATLAB to make filters MATLAB provides a few built-in functions to create ready made filter parameter A and B : E.g: butter, buttord, besself, cheby1, cheby2, ellip, freqz, filter. For our purposes the Butterworth filter will create suitable filters, help butter: 28 BUTTER Butterworth digital and analog filter design. [B,A] = BUTTER(N,Wn) designs an Nth order lowpass digital Butterworth filter and returns the filter coefficients in length N+1 vectors B (numerator) and A (denominator). The coefficients are listed in descending powers of z. The cutoff frequency Wn must be 0.0 < Wn < 1.0, with 1.0 corresponding to half the sample rate. If Wn order [B,A] [B,A] [B,A] is a two-element vector, Wn = [W1 W2], BUTTER returns an 2N bandpass filter with passband W1 < W < W2. = BUTTER(N,Wn,’high’) designs a highpass filter. = BUTTER(N,Wn,’low’) designs a lowpass filter. = BUTTER(N,Wn,’stop’) is a bandstop filter if Wn = [W1 W2]. JJ II J I Back Close Using MATLAB to make filters help buttord: BUTTORD Butterworth filter order selection. [N, Wn] = BUTTORD(Wp, Ws, Rp, Rs) returns the order N of the lowest order digital Butterworth filter that loses no more than Rp dB in the passband and has at least Rs dB of attenuation in the stopband. Wp and Ws are the passband and stopband edge frequencies, normalized from 0 to 1 (where 1 corresponds to pi radians/sample). For example, Lowpass: Wp = .1, Ws = .2 Highpass: Wp = .2, Ws = .1 Bandpass: Wp = [.2 .7], Ws = [.1 .8] Bandstop: Wp = [.1 .8], Ws = [.2 .7] BUTTORD also returns Wn, the Butterworth natural frequency (or, the "3 dB frequency") to use with BUTTER to achieve the specifications. 29 JJ II J I Back Close Using MATLAB Filter Example: Subtractive Synthesis Lecture Example The example for studying subtractive synthesis, subtract synth.m, uses the butter and filter MATLAB functions: % simple low pas filter example of subtractive synthesis Fs = 22050; y = synth(440,2,0.9,22050,’saw’); 30 % play sawtooth e.g. waveform doit = input(’\nPlay Raw Sawtooth? Y/[N]:\n\n’, ’s’); if doit == ’y’, figure(1) plot(y(1:440)); playsound(y,Fs); end %make lowpass filter and filter y [B, A] = butter(1,0.04, ’low’); yf = filter(B,A,y); [B, A] = butter(4,0.04, ’low’); yf2 = filter(B,A,y); JJ II J I Back Close % play filtererd sawtooths doit = ... input(’\nPlay Low Pass Filtered (Low order) ? Y/[N]:\n\n’, ’s’); if doit == ’y’, figure(2) plot(yf(1:440)); playsound(yf,Fs); end 31 doit = ... input(’\nPlay Low Pass Filtered (Higher order)? Y/[N]:\n\n’, ’s’); if doit == ’y’, figure(3) plot(yf2(1:440)); playsound(yf2,Fs); end %plot figures doit = input(’\Plot All Figures? Y/[N]:\n\n’, ’s’); if doit == ’y’, figure(4) plot(y(1:440)); hold on plot(yf(1:440),’r+’); plot(yf2(1:440),’g-’); end JJ II J I Back Close synth.m The supporting function, synth.m, generates waveforms as we have seen earlier in this tutorial: function y=synth(freq,dur,amp,Fs,type) % y=synth(freq,dur,amp,Fs,type) % % Synthesize a single note % % Inputs: % freq - frequency in Hz % dur - duration in seconds % amp - Amplitude in range [0,1] % Fs - sampling frequency in Hz % type - string to select synthesis type % current options: ’fm’, ’sine’, or ’saw’ if nargin<5 error(’Five arguments required for synth()’); end N = floor(dur*Fs); n=0:N-1; if (strcmp(type,’sine’)) y = amp.*sin(2*pi*n*freq/Fs); 32 JJ II J I Back Close elseif (strcmp(type,’saw’)) T = (1/freq)*Fs; ramp = (0:(N-1))/T; y = ramp-fix(ramp); y = amp.*y; y = y - mean(y); % period in fractional samples elseif (strcmp(type,’fm’)) 33 t = 0:(1/Fs):dur; envel = interp1([0 dur/6 dur/3 dur/5 dur], [0 1 .75 .6 0], 0:(1/Fs):dur); I_env = 5.*envel; y = envel.*sin(2.*pi.*freq.*t + I_env.*sin(2.*pi.*freq.*t)); else error(’Unknown synthesis type’); end % smooth edges w/ 10ms ramp if (dur > .02) L = 2*fix(.01*Fs)+1; % L odd ramp = bartlett(L)’; % odd length L = ceil(L/2); y(1:L) = y(1:L) .* ramp(1:L); y(end-L+1:end) = y(end-L+1:end) .* ramp(end-L+1:end); end JJ II J I Back Close synth.m (Cont.) Note the sawtooth waveform generated here has a non-linear up slope: 0.2 0.15 34 0.1 0.05 0 −0.05 −0.1 −0.15 0 10 20 30 40 50 60 70 80 90 100 This is created with: ramp = (0:(N-1))/T; y = ramp-fix(ramp); fix rounds the elements of X to the nearest integers towards zero. This form of sawtooth sounds slightly less harsh and is more suitable for audio synthesis purposes. JJ II J I Back Close Wavetable Synthesis Examples Simple form as discussed in Lectures is a simple creation one sine wave and one saw and then some simple cross-fading between the waves. The simple example , : % simple 35 example of Wavetable synthesis f1 = 440; f2 = 500; f3 = 620; Fs = 22050; %Create a single sine waves of frequencie f1 y1 = synth(f1,1/f1,0.9,Fs,’sine’); doit = input(’\nPlay/Plot Raw Sine y1 looped for 10 ... seconds? Y/[N]:\n\n’, ’s’); if doit == ’y’, figure(1) plot(y1); loopsound(y1,Fs,10*Fs/f1); end %Create a single Saw waves of frequencie f2 y2 = synth(f2,1/f2,0.9,Fs,’saw’); JJ II J I Back Close doit = input(’\nPlay/Plot Raw saw y2 looped for 10 ... seconds? Y/[N]:\n\n’, ’s’); if doit == ’y’, figure(2) plot(y2); loopsound(y2,Fs,10*Fs/f2); end 36 %concatenate wave ywave = [y1 , y2]; % Create Cross fade half width of wave y1 for xfade window xfadewidth = floor(Fs/(f1*2)); ramp1 = (0:xfadewidth)/xfadewidth; ramp2 = 1 - ramp1; doit = input(’\nShow Crossfade Y/[N]:\n\n’, ’s’); if doit == ’y’, figure(4) plot(ramp1); hold on; plot(ramp2,’r’); end; %apply crossfade centered over the join of y1 and y2 pad = (Fs/f1) + (Fs/f2) - 2.5*xfadewidth; JJ II J I Back Close xramp1 = [ones(1,1.5*xfadewidth) , ramp2, zeros(1,pad)]; xramp2 = [zeros(1,1.5*xfadewidth) , ramp1, ones(1,pad)]; % Create two period waveforms to fade between ywave2 = [y1 , zeros(1,Fs/f2)]; ytemp = [zeros(1,Fs/f1), y2]; ywave = ywave2; % do xfade 37 % add two waves together over the period modulated by xfade ramps % (recall .* to multiply matrices element by element % NOT MATRIX mutliplication ywave2 = xramp1.*ywave2 + xramp2.*ytemp; doit = input(’\nPlay/Plot Additive Sines together? Y/[N]:\n\n’, ’s’); if doit == ’y’, figure(5) subplot(4,1,1); plot(ywave); hold off set(gca,’fontsize’,18); ylabel(’Amplitude’); JJ II J I Back Close title(’Wave 1’); set(gca,’fontsize’,18); subplot(4,1,2); plot(ytemp); set(gca,’fontsize’,18); ylabel(’Amplitude’); title(’Wave 2’); set(gca,’fontsize’,18); subplot(4,1,3); plot(xramp1); hold on plot(xramp2,’r’) hold off set(gca,’fontsize’,18); ylabel(’Amplitude’); title(’Crossfade Masks’); set(gca,’fontsize’,18); subplot(4,1,4); plot(ywave2); set(gca,’fontsize’,18); ylabel(’Amplitude’); title(’WaveTable Synthesis’); set(gca,’fontsize’,18); loopsound(ywave2,Fs,10*Fs/(f1 + f2)); end 38 JJ II J I Back Close RECAP: Wavetable synthesis:Dynamic Waveshaping (1) Simplest idea: Linear crossfading • Crossfade from one wavetable to the next sequentially. 39 • Crossfade = apply some envelope to smoothly merge waveforms. JJ II J I Back Close Simple MATLAB Example: Linear Crossfading % Create Cross fade half width of wave y1 for xfade window xfadewidth = floor(Fs/(f1*2)); ramp1 = (0:xfadewidth)/xfadewidth; ramp2 = 1 - ramp1; 40 %apply crossfade centered over the join of y1 and y2 pad = (Fs/f1) + (Fs/f2) - 2.5*xfadewidth; xramp1 = [ones(1,1.5*xfadewidth) , ramp2, zeros(1,pad)]; xramp2 = [zeros(1,1.5*xfadewidth) , ramp1, ones(1,pad)]; % Create two period waveforms to fade between ywave2 = [y1 , zeros(1,Fs/f2)]; ytemp = [zeros(1,Fs/f1), y2]; % do xfade % add two waves together over the period modulated by xfade ramps ywave2 = xramp1.*ywave2 + xramp2.*ytemp; JJ II J I Back Close Simple MATLAB Example: Linear Crossfading (Cont.) Amplitude Wave 1 1 0 −1 0 20 40 60 80 100 41 0.5 0 −0.5 0 Amplitude Amplitude Amplitude Wave 2 20 40 60 Crossfade Masks 80 100 20 40 60 WaveTable Synthesis 80 100 80 100 1 0.5 0 0 1 0 −1 0 20 40 60 Note: This sort of technique is useful to create an ADSR envelope in MATLAB JJ II J I Back Close