%Script for simulating wavetable synthesis and seeing aliasing.

%The script allows you to specify a sample rate, a playback frequency of

% a wavetable, and to specify an amount of aliasing to see.  Increasing

% amounts of aliasing can be seen by increasing the aliasing factor.

 

 

 

SAMPLE_RATE = 32768;%Set the sampling rate

 

NYQUIST_RATE = SAMPLE_RATE/2;%Figure out the Nyquist Rate

 

NUM_OF_SAMPLES = 256;%This will be the number of samples in the wavetable.

 

PLAYBACK_FREQUENCY = 2000; %The frequency of the note we are simulating

 

NUMBER_OF_PLAYBACK_CYCLES = 25;%The number of cycles of playback of the wavetable

 

ALIASING_FACTOR = 1;

 

NUM_OF_ALIASES = ALIASING_FACTOR*NYQUIST_RATE/PLAYBACK_FREQUENCY;%The wavetable is built from summing together sine wave aliases

 

%Make large wavetable containing the 128 samples of each of the first

%2000 harmonics of a 1Hz sine wave

sin_table = zeros(2000,NUM_OF_SAMPLES);

p = 1:NUM_OF_SAMPLES;

for z = 1:2000

    for y = 1:NUM_OF_SAMPLES

        sin_table(z,y) = sin(2.*pi.*z.*y./NUM_OF_SAMPLES);

    end

end

%plot(p,sin_table);

 

wavetable = zeros(1, NUM_OF_SAMPLES);

 

%This may seem unnecessary. We are creating a sawtooth wavetable to make

%a square wave.  But, this is how it's done in my synth and that's

%particularly what I wanted to simulate. We can make square

%waves of various pulse widths by adding together square waves with

%different phase angles between them.

for k = 1:NUM_OF_SAMPLES

    for n = 1:NUM_OF_ALIASES

        wavetable(1,k) = wavetable(1,k) + (1/n).*(sin_table(n,k).*(cos((n-1).*pi./(NUM_OF_ALIASES*2))).^2);

    end

end

 

 

%This process below simulates a wavetable lookup oscillator for generating

%a square wave with 50% pulse width, or duty cycle.

phase_accumulator = 0;

wavetable_lookup_index = 0;

wavetable_reverse_lookup_index = 0;

wavetable_divisor = SAMPLE_RATE/NUM_OF_SAMPLES;

 

%Make a matrix to hold the samples of the wavetable playback

NUMBER_OF_PLAYBACK_SAMPLES = ceil(SAMPLE_RATE*NUMBER_OF_PLAYBACK_CYCLES/PLAYBACK_FREQUENCY);

playback = zeros(1, NUMBER_OF_PLAYBACK_SAMPLES);

index = 1;

 

for f = 1:PLAYBACK_FREQUENCY:(SAMPLE_RATE*NUMBER_OF_PLAYBACK_CYCLES)

        phase_accumulator = phase_accumulator + PLAYBACK_FREQUENCY;

       

        if (phase_accumulator > SAMPLE_RATE)

            phase_accumulator = phase_accumulator - SAMPLE_RATE;

        end

       

        wavetable_lookup_index = floor(phase_accumulator/wavetable_divisor);

       

        if(wavetable_lookup_index < 1)

            wavetable_lookup_index = 1;

        end

       

        if(wavetable_lookup_index > NUM_OF_SAMPLES/2)

            wavetable_reverse_lookup_index = wavetable_lookup_index - NUM_OF_SAMPLES/2;

        else

            wavetable_reverse_lookup_index = wavetable_lookup_index + NUM_OF_SAMPLES/2;

        end

       

         if(wavetable_reverse_lookup_index < 1)

            wavetable_reverse_lookup_index = 1;

        end

       

        playback(1, index) = wavetable(1, wavetable_lookup_index) - wavetable(1, wavetable_reverse_lookup_index);

        index = index + 1;

end

 

%Plot the wavetable and its FFT.

k = 1:NUMBER_OF_PLAYBACK_SAMPLES;

T = 1/SAMPLE_RATE;

subplot(2,1,1);

plot(T*k,playback);

NFFT = 2^nextpow2(NUMBER_OF_PLAYBACK_SAMPLES*2); % Next power of 2 from length of y

Y = fft(playback, NFFT)/NUMBER_OF_PLAYBACK_SAMPLES;

f = SAMPLE_RATE/2*linspace(0,1,NFFT/2+1);

subplot(2,1,2);

plot(f,2*abs(Y(1:NFFT/2+1)))

print('-dpng', 'test.png');

 

%plot(T*k,fft(playback,k));