function [ output_args ] = digiSound( sampleFrequencyUsed, bitResolutionUsed, quantizationMode, phaseChange, waveSelect, toneFrequency, DA, plotLength, soundPlay)
% ---/// digiSound \\\---
%
% Usage: digiSound(sampleFrequencyUsed, bitResolutionUsed, quantizationMode, phaseChange, waveSelect, toneFrequency, DA, plotLength, soundPlay)
% 
% sampleFrequencyUsed - sets the sample frequncy used to sample the tone.
% bitResolutionUsed - sets the bit resoultion of the sample.
% quantizationMode - is optional and sets the quantization to linear (0) 
% or non-linear (1), if not set linear quantization (0) will be used.
% phaseChange - is optional and sets the phase of the tone 0-90... if not 
% set 0 will be used.
% waveSelect - is optional and set as 0 for Simple (sine) or 1 for Complex 
% wave form, if not set Simple (0) will be used.
% toneFrequency - is optional and sets the frequenct of the tone, if not 
% set 440Hz will be used.
% DA - is optional and if set to 1 displays a low pass filtered version 
% of the sample wave form, if not set the analogue output will not (0) 
% be shown.
% plotLength - is optional and sets the length of the plot in ms, if not
% set 5ms is used.
% soundPlay - is optional and set to 1 play back the two wave forms, if 
% not set no sound (0) will be played.
% 
%
% Example: digiSound(1760,4)
% Which will show a simple wave form of 440Hz sampled with a sample 
% frequency of 1760Hz, and four bits resolution linear quantization.
% 
% Example: digiSound(11025,8,1)
% Which will sample the simple wave form with a sample frequency of 
% 11025Hz, and 8 bit non-linear quantization
% 
% Example: digiSound(22050,8,0,0,1,440,1,5,1)
% Which will sample a complex wave form based around 440Hz with a 
% sample frequency of 22050, 8 bit linear quantization, and it will 
% plot (5ms) the analogue output, as well as play both the original and 
% the sampled wave forms.
% 
% 

if ~(exist('sampleFrequencyUsed','var')) || ~(exist('bitResolutionUsed','var'))
    fprintf('\nUsage: digiSound(sampleFrequencyUsed, bitResolutionUsed, quantizationMode, phaseChange, waveSelect, toneFrequency, DA, soundPlay)\n\nsampleFrequencyUsed sets the sample frequncy used to sample the tone.\nbitResolution sets the bit resoultion of the sample.\nquantizationMode is optional and sets the quantization to linear (0) or non-linear (1), if not set linear quantization (0) will be used.\nphaseChange is optional and sets the phase of the tone 0-90... if not set 0 will be used.\nwaveSelect is optional and set as ''s'' for Simple (sine) or ''c'' for Complex wave form, if not set Simple (0) will be used.\ntoneFrequency is optional and sets the frequenct of the tone, if not set 440Hz will be used.\nDA is optional and if set to 1 displays a low pass filtered version of the sample wave form, if not set the analogue output will not (0) be shown.\nsoundPlay is optional and set to 1 play back the two wave forms, if not set no sound (0) will be played.\n\n');
    return
end

if ~(exist('toneFrequency','var'))
    toneFrequency = 440;
end

if ~(exist('quantizationMode','var'))
    quantizationMode = 0;
end

if ~(exist('phaseChange','var'))
    phaseChange = 0;
end

if ~(exist('waveSelect','var'))
    waveSelect = 0;
end

if ~(exist('DA','var'))
    DA = 0;
end

if ~(exist('plotLength','var'))
    plotLength = 5;
end

if ~(exist('soundPlay','var'))
    soundPlay = 0;
end

phaseToUse = pi*(phaseChange/90);
sampleFrequency = 192000;
soundLength = 2;
bitResolution = 2^(bitResolutionUsed-1);

% Create quantization vector
quantizationVector = [];
decimalCorrection = 1/bitResolution;
for i=1:bitResolution
    quantizationLevel = i*decimalCorrection;
    if (quantizationMode)
        quantizationVector = sort([quantizationVector,-(quantizationLevel*quantizationLevel),((quantizationLevel-decimalCorrection)*(quantizationLevel-decimalCorrection))]);
        typeOfQuantization = 'non-linear';
    else
        quantizationVector = sort([quantizationVector,-quantizationLevel,quantizationLevel-decimalCorrection]);
        typeOfQuantization = 'linear';
    end
end

timeVector = (0:soundLength*sampleFrequency)./sampleFrequency;
% Make simple waveform
simpleWaveForm = sin(2*pi*toneFrequency.*timeVector+phaseToUse).*.95;
maxOfWaveForm = max(abs(simpleWaveForm));
% Make complex waveform
waveForm1 = sin(2*pi*(toneFrequency*1)*timeVector);
waveForm2 = sin(2*pi*(toneFrequency*0.5)*timeVector);
waveForm3 = sin(2*pi*(toneFrequency*5)*timeVector);
complexWaveForm = (waveForm1.*waveForm2.*waveForm3);
maxOfComplexWaveForm = max(abs(complexWaveForm));
levelFactor = maxOfWaveForm/maxOfComplexWaveForm;
complexWaveForm = complexWaveForm.*levelFactor;
% Set type of waveform
if (waveSelect)
    waveForm = complexWaveForm;
else
    waveForm = simpleWaveForm;
end
% Plot original sound wave
figure();
set(gcf,'name','Digital sound representation','numbertitle','off')
plot(timeVector*1000,waveForm,'g-','LineWidth',2);
hold on;

% Sample waveForm
downSampledWaveForm = [];
for i=0:length(waveForm)
    if (length(waveForm)>=(i*(round(sampleFrequency/sampleFrequencyUsed))))
        sampledValue = roundToVector(waveForm(i*(round(sampleFrequency/sampleFrequencyUsed))+1),quantizationVector);
        for k=1:round(sampleFrequency/sampleFrequencyUsed)
            downSampledWaveForm = [downSampledWaveForm,sampledValue];
        end
     end
end

% Make downSampledWaveForm equally long as timeVector
downSampledWaveForm = downSampledWaveForm(1:length(timeVector));

% Plot quantized wave form
plot(timeVector*1000,downSampledWaveForm,'k-')

if DA
    % Lowpass filter the quantizedSampledWaveForm  ---
    order = 4;
    cutoffFrequency = sampleFrequencyUsed/2;
    [b,a] = butter(order, cutoffFrequency/(sampleFrequency/2), 'low');
    sampledSoundToPlay = filter(b, a, downSampledWaveForm);
    plot(timeVector*1000,sampledSoundToPlay,'r-')  
end

title(['Frequency: ',num2str(toneFrequency),' Hz. Phase: ',num2str(phaseChange),'. Sample frequency: ', num2str(sampleFrequencyUsed),' Hz. Bit resolution: ', num2str(bitResolutionUsed),' ',typeOfQuantization])
if DA
    legend('Wave form to sample','Digital representation','Analogue output')
else
    legend('Wave form to sample','Digital representation')
end

signalToQuantizationNoiseRatio = round(100*(20*log10(2^bitResolutionUsed)))/100;

ylabel(['Amplitude levels (SQNR: ',num2str(signalToQuantizationNoiseRatio),' dB)']);
xlabel('Time (ms)');
xlim([0,plotLength]);
ylim([-1.1,1.1]);

stepSize = round((bitResolution/2)/bitResolutionUsed);

showQuantizationVector = [];
for i=1:stepSize:(length(quantizationVector))
    showQuantizationVector = sort([showQuantizationVector,quantizationVector(i)]);
end

for i=1:length(showQuantizationVector)
    line('XData', [0 length(timeVector)], 'YData', [showQuantizationVector(i) showQuantizationVector(i)], 'LineStyle', ':', 'LineWidth', 1, 'Color','c')
end

hold off;

if soundPlay
	attenuationFactor = 1/max(abs(waveForm));
	attenuatedWaveform = waveForm.*attenuationFactor;
	Fs = 44100;
	[P,Q] = rat(Fs/sampleFrequency);
	playableWaveForm = resample(attenuatedWaveform,P,Q);

	attenuationFactor = 1/max(abs(sampledSoundToPlay));
	attenuatedWaveform = sampledSoundToPlay.*attenuationFactor;
	playableSampledWaveForm = resample(attenuatedWaveform,P,Q);

	originalSound = audioplayer(playableWaveForm,Fs);
	sampledSound = audioplayer(playableSampledWaveForm,Fs);
	playblocking(originalSound)
	playblocking(sampledSound)
end

end

function newnums = roundToVector(inputValue,roundVector)
newnums=inputValue;
roundVector=reshape(unique(roundVector),1,[]);
for i=numel(inputValue):-1:1
    if ~any(inputValue(i)==roundVector)
        DIFFs=abs(roundVector-inputValue(i));
        if inputValue(i)>=0
            [~,ind]=min(DIFFs(:,end:-1:1));
            newnums(i)=roundVector(length(DIFFs)-ind+1);
        elseif inputValue(i)<0
            [~,ind]=min(DIFFs);
            newnums(i)=roundVector(ind);
        end
    end
end
end
