diff --git a/.DS_Store b/.DS_Store index dd306f7..bc2a648 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/README.md b/README.md index 1807172..2a81b49 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Will add member names shortly ## Function Prototypes -Templates to create your own functions. +Templates to create your own functions. Please commit code in either src/ (the base directopry) or src/NotWorking (please dont commit in any other subfolder). ### Wave generating function ``` @@ -57,10 +57,10 @@ where LOW, MED, HIGH are user-selected variables of any value. ## Useful websites - - https://learningsynths.ableton.com - - https://learningsynths.ableton.com/en/playground - - https://blog.demofox.org/diy-synthesizer/ - - http://portaudio.com/ - - https://ccrma.stanford.edu/software/stk/ - - https://cycling74.com/products/max - - http://msp.ucsd.edu/software.html + - [Learning Synths](https://learningsynths.ableton.com) + - [Learning Synths Playground](https://learningsynths.ableton.com/en/playground) + - [DIY Synthesisers](https://blog.demofox.org/diy-synthesizer/) + - [Port Audio (audio I/O library)](http://portaudio.com/) + - [Synthesis ToolKit in C++](https://ccrma.stanford.edu/software/stk/) + - [Max](https://cycling74.com/products/max) + - [Software by Miller Puckette](http://msp.ucsd.edu/software.html) diff --git a/src/.DS_Store b/src/.DS_Store index a262e39..385d2ba 100644 Binary files a/src/.DS_Store and b/src/.DS_Store differ diff --git a/src/Filter/AnuragDampenTarget.m b/src/Filter/AnuragDampenTarget.m new file mode 100644 index 0000000..3b325d3 --- /dev/null +++ b/src/Filter/AnuragDampenTarget.m @@ -0,0 +1,33 @@ +function output_x = AnuragDampenTarget(x, Fs,LOW, MID, HIGH) +%Dampen a range of frequencies a percentage around the target frequency +%Also maintain the other frequencies so that the target is muted +%percentage is expressed as a number between 0 and 1. +%target is the midpoint of the frequency range to dampen +%x and Fs are the signal and frequency +% CONTRIBUTORS: +% Anurag Jadhav: function creator + +% Detailed explanation goes here + TARGET = MID; + AreaPercentage = 0.15; + len = length(x); %get length of the input + F = Fs * ((-len/2) : ((len/2) - 1)) / len; + lenf = length(F); + Mod_Freq = fftshift(fft(x)); %Fourier Transform of the input signal + output = zeros([1,lenf]); % zero array of size Mod_freq + %set the bounds + lowerBound = (1-AreaPercentage) * TARGET; + upperBound = (1+AreaPercentage) * TARGET; +%% Dampen the target frequencies and maintain the others + for n = 1:lenf + if ((lowerBound < abs(F(n))) && abs(F(n)) < upperBound) + output(n) = 0.5; + else + output(n) = 1; + end + end +%%Filter the original signal and transform + filtered_Mod_Freq = fftshift(Mod_Freq .* output); + output_x = real(ifft(filtered_Mod_Freq)); + +end \ No newline at end of file diff --git a/src/Filter/AnuragEnhanceTarget.m b/src/Filter/AnuragEnhanceTarget.m new file mode 100644 index 0000000..97d990a --- /dev/null +++ b/src/Filter/AnuragEnhanceTarget.m @@ -0,0 +1,34 @@ +function output_x = AnuragEnchanceTarget(x, Fs,LOW, MID, HIGH) +%Amplify a range of frequencies a percentage around the target frequency +%Also damnpen the other frequencies so that the target is easier to hear +%percentage is expressed as a number between 0 and 1. +%target is the midpoint of the frequency range to amplify +%x and Fs are the signal and frequency +% CONTRIBUTORS: +% Anurag Jadhav: function creator + +% Detailed explanation goes here + TARGET = MID; + AreaPercentage = 0.15; + len = length(x); %get length of the input + F = Fs * ((-len/2) : ((len/2) - 1)) / len; + lenf = length(F); + Mod_Freq = fftshift(fft(x)); %Fourier Transform of the input signal + output = zeros([1,lenf]); % zero array of size Mod_freq + + %set the bounds + lowerBound = (1-AreaPercentage) * TARGET; + upperBound = (1+AreaPercentage) * TARGET; +%% Amplify the target frequencies and dampen the others + for n = 1:lenf + if ((lowerBound < abs(F(n))) && abs(F(n)) < upperBound) + output(n) = 2; + else + output(n) = 0.75; + end + end +%%Filter the original signal and transform + filtered_Mod_Freq = fftshift(Mod_Freq .* output); + output_x = real(ifft(filtered_Mod_Freq)); + +end \ No newline at end of file diff --git a/src/Filter/bandreject_filter.m b/src/Filter/bandreject_filter.m index 8073a9e..9d089b9 100644 --- a/src/Filter/bandreject_filter.m +++ b/src/Filter/bandreject_filter.m @@ -1,4 +1,4 @@ -function output_y = bandreject_filter(Input, Fs, Low, High) +function Output = bandreject_filter(Input, Fs, Low, High) % A filter that lets through most frequencies unaltered % but attentuates the frequencies in the specified range to % very low levels diff --git a/src/Filter/epic_effect_schluep.m b/src/Filter/epic_effect_schluep.m index 2ad7109..6ff54c3 100644 --- a/src/Filter/epic_effect_schluep.m +++ b/src/Filter/epic_effect_schluep.m @@ -15,13 +15,22 @@ function output = epic_effect_schluep(input, Fs, LOW, MED, HIGH) % HIGH: The maximum frequency the filter will amplify. A typical value for % this variable is 1000 Hz. -non_stereophonic = input(:, 1); % Removes the sterophonic property of the input sound -% by just taking the first column of data. +n = size(input, 2); -Len = length(non_stereophonic); +non_stereophonic = input; + +if (n == 1) || (n == 2) + non_stereophonic = input(:, 1); % Removes the sterophonic property of the input sound + % by just taking the first column of data. + non_stereophonic = transpose(non_stereophonic); +end + +modified_input = non_stereophonic(1, :); + +Len = length(modified_input); F = Fs * ((-Len/2) : ((Len/2) - 1)) / Len; % Creating the array of frequencies % which the FFT Shifted version of the signal can be plotted against. -inputFreq = fftshift(fft(non_stereophonic)); % Creates the Fourier Transform of the +inputFreq = fftshift(fft(modified_input)); % Creates the Fourier Transform of the % input signal. fftshift() makes it such that the zero frequency is at the % center of the array. lowAmplifyFilter = zeros(1, length(inputFreq)); @@ -35,7 +44,8 @@ for i = 1:length(lowAmplifyFilter) end end -lowPassedInput = inputFreq .* transpose(lowAmplifyFilter); %Apply the "lowAmplifyFilter". +lowPassedInput = inputFreq .* lowAmplifyFilter; %Apply the "lowAmplifyFilter". +lowPassedInput = transpose(lowPassedInput); % Adding the chorus effect. realOutput = real(ifft(fftshift(lowPassedInput))); @@ -53,3 +63,7 @@ for i = 1:100 end output = output ./ 100; % Divide by 100 to decrease the amplitude of the sound to a normal level. + +output = transpose(output); + +end \ No newline at end of file diff --git a/src/Filter/muffled_effect_schluep.m b/src/Filter/muffled_effect_schluep.m index c193a38..7e611ac 100644 --- a/src/Filter/muffled_effect_schluep.m +++ b/src/Filter/muffled_effect_schluep.m @@ -13,13 +13,22 @@ function output = muffled_effect_schluep(input, Fs, LOW, MED, HIGH) % HIGH: The maximum frequency that the low-pass filter will let pass. A % typical value for this variable is 1000 Hz. -non_stereophonic = input(:, 1); % Removes the sterophonic property of the input sound -% by just taking the first column of data. +n = size(input, 2); -Len = length(non_stereophonic); +non_stereophonic = input; + +if (n == 1) || (n == 2) + non_stereophonic = input(:, 1); % Removes the sterophonic property of the input sound + % by just taking the first column of data. + non_stereophonic = transpose(non_stereophonic); +end + +modified_input = non_stereophonic(1, :); + +Len = length(modified_input); F = Fs * ((-Len/2) : ((Len/2) - 1)) / Len; % Creating the array of frequencies % which the FFT Shifted version of the signal can be plotted against. -inputFreq = fftshift(fft(non_stereophonic)); % Creates the Fourier Transform of the +inputFreq = fftshift(fft(modified_input)); % Creates the Fourier Transform of the % input signal. fftshift() makes it such that the zero frequency is at the % center of the array. lowPassFilter = zeros(1, length(inputFreq)); @@ -33,7 +42,8 @@ for i = 1:length(lowPassFilter) end end -lowPassedInput = inputFreq .* transpose(lowPassFilter); %Apply the low-pass filter. +lowPassedInput = inputFreq .* lowPassFilter; %Apply the low-pass filter. +lowPassedInput = transpose(lowPassedInput); % Adding a slight reverb effect. realOutput = real(ifft(fftshift(lowPassedInput))); @@ -50,6 +60,10 @@ output = (realOutput + delayedOutput) ./ 2.0; % Adds the "realOutput" and "de % vectors to create a reverb effect. Divides by 2 to avoid clipping % effects. +output = transpose(output); + +end + diff --git a/src/Filter/seperate_prevalent_schluep.m b/src/Filter/seperate_prevalent_schluep.m index 3fbc7a6..a1312c8 100644 --- a/src/Filter/seperate_prevalent_schluep.m +++ b/src/Filter/seperate_prevalent_schluep.m @@ -14,13 +14,22 @@ function output = seperate_prevalent_schluep(input, Fs, LOW, MED, HIGH) % not be attenuated. A good range of values is usually 250-500 Hz, but it % depends on the input sound. -non_stereophonic = input(:, 1); % Removes the sterophonic property of the input sound -% by just taking the first column of data. +n = size(input, 2); -Len = length(non_stereophonic); +non_stereophonic = input; + +if (n == 1) || (n == 2) + non_stereophonic = input(:, 1); % Removes the sterophonic property of the input sound + % by just taking the first column of data. + non_stereophonic = transpose(non_stereophonic); +end + +modified_input = non_stereophonic(1, :); + +Len = length(modified_input); F = Fs * ((-Len/2) : ((Len/2) - 1)) / Len; % Creating the array of frequencies % which the FFT Shifted version of the signal can be plotted against. -inputFreq = fftshift(fft(non_stereophonic)); % Creates the Fourier Transform of the +inputFreq = fftshift(fft(modified_input)); % Creates the Fourier Transform of the % input signal. fftshift() makes it such that the zero frequency is at the % center of the array. bandPassFilter = zeros(1, length(inputFreq)); @@ -53,10 +62,12 @@ for i = 1:length(bandPassFilter) end end -bandPassedInput = inputFreq .* transpose(bandPassFilter); %Apply the Band-Pass Filter. +bandPassedInput = inputFreq .* bandPassFilter; %Apply the Band-Pass Filter. output = real(ifft(fftshift(bandPassedInput))); +end + diff --git a/App/.DS_Store b/src/Generators/.DS_Store similarity index 100% rename from App/.DS_Store rename to src/Generators/.DS_Store diff --git a/src/Generators/generate_cosine.m b/src/Generators/generate_cosine.m new file mode 100644 index 0000000..8a013ed --- /dev/null +++ b/src/Generators/generate_cosine.m @@ -0,0 +1,25 @@ +function x = generate_cosine(amplitude, frequency, phase, fs, duration, duty) +% GENERATE_WAVENAME: returns a matrix of sampled WAVENAME wave + +% CONTRIBUTORS: +% Mekhi Ellington: Original Creator + +% DOCUMENTATION: +% phase shift is in number of periods +% fs is the sampling frequency: how many sample points per second +% duration is time in seconds +% duty is a number between 0 and 1 + + % initialize local variables from input arguments + n = fs * duration; % number of samples (length of matrix) + dt = 1 / fs; % sampling period: time between two sample points + + % initialize a one dimensional zero matrix to be populated + x = zeros(1, n); + + % populate the matrix + for i = 1:n + t = i * dt; + x(i) = amplitude * cos(2*pi*frequency*t-phase); + end +end \ No newline at end of file diff --git a/src/Generators/generate_heartbeat.m b/src/Generators/generate_heartbeat.m new file mode 100644 index 0000000..40230d6 --- /dev/null +++ b/src/Generators/generate_heartbeat.m @@ -0,0 +1,46 @@ +function x = generate_heartbeat(amplitude, frequency, phase, fs, duration, duty) +% GENERATE_SINE: returns a matrix of sampled heart monitor wave + +% CONTRIBUTORS: +% Alex Nguyen: Original Author +% Conner Hsu: Reviewed Code and Assisted in polishing + +% DOCUMENTATION: +% phase shift is in number of periods +% fs is the sampling frequency: how many sample points per second +% duration is time in seconds +% duty cycle should be a number between 0 and 0.5. + % duty of 0 or less would return 0 for all sample points + % duty of 0.5 or less would return a heartbeat signal since there would be + % equal amount of space within 1 period to have the right and left sides be equal + % duty of greater than 0.5 but less than 1 would return a slope starting at that duty i.e. + % the left side but leaving little room to the right side + % duty of between 1 and 2 would give a sawtooth wave in the +amplitude. + % duty greater than 2 would return 0 for all sample points + + + % initialize local variables from input arguments + n = fs * duration; % number of samples (length of matrix) + dt = 1 / fs; % sampling period: time between two sample points + + + % initialize a one dimensional zero matrix to be populated + x = zeros(1, n); + + % populate the matrix + for i = 1:n + t = i * dt; % time at the i'th sample + st = mod(frequency * t - phase, 1); + + if (duty-(duty / 2) < st && st < duty) + slope = amplitude / duty; + intercept = -0.5 * amplitude; + x(i) = slope * st + intercept; + elseif (duty < st && st < duty+(duty / 2)) + slope = amplitude / duty; + intercept = -amplitude; + x(i) = slope * st + (1.5 * intercept); + else + x(i) = 0; + end +end \ No newline at end of file diff --git a/src/Generators/generate_pulse.m b/src/Generators/generate_pulse.m new file mode 100644 index 0000000..2f9c316 --- /dev/null +++ b/src/Generators/generate_pulse.m @@ -0,0 +1,33 @@ +function x = generate_pulse(amplitude, frequency, phase, fs, duration, duty) +% GENERATE_puse: returns a matrix of sampled pulse wave + +% CONTRIBUTORS: +% Brian Tran: Created the wave + +% DOCUMENTATION: +% phase shift is in number of periods +% fs is the sampling frequency: how many sample points per second +% duration is time in seconds +% duty is a number between 0 and 1 + + % initialize local variables from input arguments + n = fs * duration; % number of samples (length of matrix) + dt = 1 / fs; % sampling period: time between two sample points + % initialize a one dimensional zero matrix to be populated + x = zeros(1, n); + f0=1e+6; % 1MHz + Fs=3e+6; + Tf=0.001; % 1 millisecond + t=0:1/Fs:Tf-1/Fs; + td=0.1; % duty cycle + A0=10; % 10 Volts + F=0; + N=1000; % Number of points + + % populate the matrix + for n = 1:N + F=F+(1/n)*cos(n*2*pi*f0*t).*sin(n*pi*td); + end + F=F*(2*A0/pi); + F=F+A0*td; +end \ No newline at end of file diff --git a/src/Generators/generate_trapezoid.m b/src/Generators/generate_trapezoid.m new file mode 100644 index 0000000..6c612b5 --- /dev/null +++ b/src/Generators/generate_trapezoid.m @@ -0,0 +1,58 @@ +function x = generate_trapezoid(amplitude, frequency, phase, fs, duration, duty) +% GENERATE_TRAPEZOID: returns a matrix of sampled square wave + +% CONTRIBUTORS: +% Daniel Doan: Author + +% DOCUMENTATION: +% phase shift is in number of periods +% fs is the sampling frequency: how many sample points per second +% duration is time in seconds +% duty cycle should be a number between 0 and 1. + % duty of 0.5 would have 2 trapezoids in first half of each cycle + % example of wave with duty of 0.5, where the peaks are amplitude/2: + % + % ____ + % / \ + % / \ ________________ + % \ / + % \____/ + % + + + +% initialize local variables from input arguments + n = fs * duration; % number of samples (length of matrix) + dt = 1 / fs; % sampling period: time between two sample points + + % initialize a one dimensional zero matrix to be populated + x = zeros(1, n); + + % populate the matrix + for i = 1:n + t = i * dt; + + % periodic ramp from 0 to 1 + % progression through a cycle + st = mod(frequency * t - phase, 1); + slope = (amplitude/2) / (duty/8); + if(st < duty) + if(st <= duty/8) + x(i) = slope * st; + else + if(st <= 5*duty/8) + x(i) = amplitude/2 - slope * (st-(3*duty/8)); + end + if(st <= 3*duty/8) + x(i) = amplitude/2; + end + if(st >= 5*duty/8) + x(i) = -amplitude/2; + end + end + if(st >= 7* duty/8) + x(i) = -amplitude/2 + slope*(st-(7*duty/8)); + end + end + end +end \ No newline at end of file diff --git a/src/Helper/MIDIDarell.m b/src/Helper/MIDIDarell.m index 19491c4..2253b73 100644 --- a/src/Helper/MIDIDarell.m +++ b/src/Helper/MIDIDarell.m @@ -1,6 +1,6 @@ function output = MIDIDarell(dur,Fs) %Darell Chua Yun Da -% Detailed explanation goes here +% Use Qwerty Keys for each sound frequency. freq = [330 350 370 392 415 440 466 494 523 554]; charls = ["q" "w" "e" "r" "t" "y" "u" "i" "o" "p"]; diff --git a/src/NotWorking/fade_in.m b/src/Helper/fade_in.m similarity index 70% rename from src/NotWorking/fade_in.m rename to src/Helper/fade_in.m index 22bef76..bebb07f 100644 --- a/src/NotWorking/fade_in.m +++ b/src/Helper/fade_in.m @@ -12,16 +12,30 @@ function output = fade_in(input, time) len = length(input); + % need to use whole number for time + time = round(time); + % if time parameter longer than signal, treat time as % the duration of original signal if time > len - time = len + time = len; + end + + % in order to create array, time >=1 + % if not, it's arbitrarily set to 1 + % in which case the fade_in effect + % is virtually nonexistent + if time < 1 + time = 1; end % set multiplier as 1D array % fade in effect: from no volume to full volume of signal multiplier = (1 : time) / time; - + + while length(multiplier) < len + multiplier = [multiplier 1]; + end % the resulting fade-in output output = input .* multiplier; end diff --git a/src/NotWorking/fade_out.m b/src/Helper/fade_out.m similarity index 70% rename from src/NotWorking/fade_out.m rename to src/Helper/fade_out.m index f50812b..954a1bb 100644 --- a/src/NotWorking/fade_out.m +++ b/src/Helper/fade_out.m @@ -11,18 +11,33 @@ function output = fade_out(input, time) len = length(input); + % need to use time as a whole number + time = round(time); + % if time parameter longer than signal, treat time as % the duration of original signal if time > len time = len end + % in order to create array, time >=1 + % if not, it's arbitrarily set to 1 + % in which case the fade_in effect + % is virtually nonexistent + if time < 1 + time = 1; + end + % set multiplier as 1D array multiplier = (1 : time) / time; % fade out effect: from full volume of signal to no volume - multiplier = flip(multiplier) + multiplier = flip(multiplier); + + while length(multiplier) < len + multiplier = [multiplier 0]; + end % the resulting fade-in output output = input .* multiplier; diff --git a/src/Instruments/generate_arcoStrings.m b/src/Instruments/generate_arcoStrings.m new file mode 100644 index 0000000..51a58fb --- /dev/null +++ b/src/Instruments/generate_arcoStrings.m @@ -0,0 +1,41 @@ +function x = generate_arcoStrings(amplitude, frequency, phase, fs, duration, duty) +% GENERATE_ARCOSTRINGS: returns a matrix of sampled waveform similar to +% strings played arco. + +% CONTRIBUTORS: +% Brandon Roberts: Original author +% MuseScore: Reference source for overtone information + +% DOCUMENTATION: +% phase shift is in number of periods +% fs is the sampling frequency: how many sample points per second +% duration is time in seconds +% duty does not apply for instruments + + + % setup needed variables + n = fs * duration; % total data points + dt = 1 / fs; % space between samples + + % initialize template time scale + t = [1:n].*dt - phase; + f = frequency .* (1 + 0.0002 .* sin(10.*pi.*t)./t); %frequency vibrato + + % generate proper fundamental and overtones + x = (amplitude .* sin(2.*pi.*f.*t)) ... %fundamental (first partial) + + (0.237992723.*amplitude .* sin(4.*pi.*f.*t)) ... %second partial + + (0.0523347308.*amplitude .* sin(6.*pi.*f.*t)) ... %third partial + + (0.124586119.*amplitude .* sin(8.*pi.*f.*t)) ... %fourth partial + + (0.0854326396.*amplitude .* sin(10.*pi.*f.*t)) ... %fifth partial + + (0.0578741297.*amplitude .* sin(12.*pi.*f.*t)) ... %sixth partial + + (0.0291070237.*amplitude .* sin(14.*pi.*f.*t)) ... %seventh partial + + (0.0270171595.*amplitude .* sin(16.*pi.*f.*t)) ... %eighth partial + + (0.0290818446.*amplitude .* sin(18.*pi.*f.*t)) ... %ninth partial + + (0.0356787652.*amplitude .* sin(20.*pi.*f.*t)) ... %tenth partial + + (0.0112928202.*amplitude .* sin(22.*pi.*f.*t)) ... %eleventh partial + + (0.00547645126.*amplitude .* sin(24.*pi.*f.*t)) ... %twelth partial + + (0.00800694943.*amplitude .* sin(26.*pi.*f.*t)) ... %thirteenth partial + + (0.00463295187.*amplitude .* sin(28.*pi.*f.*t)); %fourteenth partial + x = x .* (1 + 0.1 .* sin(10.*pi.*t)); %volume vibrato +end + diff --git a/src/Instruments/generate_bassoon.m b/src/Instruments/generate_bassoon.m new file mode 100644 index 0000000..21470ea --- /dev/null +++ b/src/Instruments/generate_bassoon.m @@ -0,0 +1,45 @@ +function x = generate_bassoon(amplitude, frequency, phase, fs, duration, duty) +% GENERATE_BASSOON: returns a matrix of sampled waveform similar to +% a bassoon. + +% CONTRIBUTORS: +% Brandon Roberts: Original author +% MuseScore: Reference source for overtone information + +% DOCUMENTATION: +% phase shift is in number of periods +% fs is the sampling frequency: how many sample points per second +% duration is time in seconds +% duty does not apply for instruments + + + % setup needed variables + n = fs * duration; % total data points + dt = 1 / fs; % space between samples + + % initialize template time scale + t = [1:n].*dt - phase; + f = frequency .* (1 + 0.0001 .* sin(4.*pi.*t)./t); %frequency vibrato + + % generate proper fundamental and overtones + x = (0.0934091627.*amplitude .* sin(2.*pi.*f.*t)) ... %fundamental (first partial) + + (0.0257187994.*amplitude .* sin(4.*pi.*f.*t)) ... %second partial + + (0.120530806.*amplitude .* sin(6.*pi.*f.*t)) ... %third partial + + (amplitude .* sin(8.*pi.*f.*t)) ... %fourth partial + + (0.216745656.*amplitude .* sin(10.*pi.*f.*t)) ... %fifth partial + + (0.0561137441.*amplitude .* sin(12.*pi.*f.*t)) ... %sixth partial + + (0.0300031596.*amplitude .* sin(14.*pi.*f.*t)) ... %seventh partial + + (0.0863949447.*amplitude .* sin(16.*pi.*f.*t)) ... %eighth partial + + (0.0574533965.*amplitude .* sin(18.*pi.*f.*t)) ... %ninth partial + + (0.0337819905.*amplitude .* sin(20.*pi.*f.*t)) ... %tenth partial + + (0.0576176935.*amplitude .* sin(22.*pi.*f.*t)) ... %eleventh partial + + (0.0107298578.*amplitude .* sin(24.*pi.*f.*t)) ... %twelth partial + + (0.00582622433.*amplitude .* sin(26.*pi.*f.*t)) ... %thirteenth partial + + (0.00540916272.*amplitude .* sin(28.*pi.*f.*t)) ... %fourteenth partial + + (0.00615481833.*amplitude .* sin(30.*pi.*f.*t)) ... %fifteenth partial + + (0.00480252765.*amplitude .* sin(32.*pi.*f.*t)) ... %sixteenth partial + + (0.0100473934.*amplitude .* sin(34.*pi.*f.*t)) ... %seventeenth partial + + (0.00528278041.*amplitude .* sin(36.*pi.*f.*t)); %eighteenth partial + x = x .* (1 + 0.1 .* sin(4.*pi.*t)); %volume vibrato +end + diff --git a/src/Instruments/generate_clarinet.m b/src/Instruments/generate_clarinet.m new file mode 100644 index 0000000..bb86808 --- /dev/null +++ b/src/Instruments/generate_clarinet.m @@ -0,0 +1,38 @@ +function x = generate_clarinet(amplitude, frequency, phase, fs, duration, duty) +% GENERATE_CLARINET: returns a matrix of sampled waveform similar to +% a clarinet. + +% CONTRIBUTORS: +% Brandon Roberts: Original author +% MuseScore: Reference source for overtone information + +% DOCUMENTATION: +% phase shift is in number of periods +% fs is the sampling frequency: how many sample points per second +% duration is time in seconds +% duty does not apply for instruments + + + % setup needed variables + n = fs * duration; % total data points + dt = 1 / fs; % space between samples + + % initialize template time scale + t = [1:n].*dt - phase; + f = frequency; %clarinets play without vibrato + + % generate proper fundamental and overtones. Note that the clarinet has + % heavily suppressed odd-numbered partials + x = (amplitude .* sin(2.*pi.*f.*t)) ... %fundamental (first partial) + + (0.00290397158.*amplitude .* sin(4.*pi.*f.*t)) ... %second partial + + (0.368654023.*amplitude .* sin(6.*pi.*f.*t)) ... %third partial + + (0.0733323309.*amplitude .* sin(8.*pi.*f.*t)) ... %fourth partial + + (0.299729339.*amplitude .* sin(10.*pi.*f.*t)) ... %fifth partial + + (0.0483901284.*amplitude .* sin(12.*pi.*f.*t)) ... %sixth partial + + (0.0941300303.*amplitude .* sin(14.*pi.*f.*t)) ... %seventh partial + + (0.033165423.*amplitude .* sin(16.*pi.*f.*t)) ... %eighth partial + + (0.00803526117.*amplitude .* sin(18.*pi.*f.*t)) ... %ninth partial + + (0.0131383569.*amplitude .* sin(20.*pi.*f.*t)); %tenth partial + x = x .* (1 + 0.05 .* sin(10.*pi.*t)); %slight volume vibrato added for character +end + diff --git a/src/Instruments/generate_flute.m b/src/Instruments/generate_flute.m new file mode 100644 index 0000000..0183455 --- /dev/null +++ b/src/Instruments/generate_flute.m @@ -0,0 +1,34 @@ +function x = generate_flute(amplitude, frequency, phase, fs, duration, duty) +% GENERATE_FLUTE: returns a matrix of sampled waveform similar to +% a flute. + +% CONTRIBUTORS: +% Brandon Roberts: Original author +% MuseScore: Reference source for overtone information + +% DOCUMENTATION: +% phase shift is in number of periods +% fs is the sampling frequency: how many sample points per second +% duration is time in seconds +% duty does not apply for instruments + + + % setup needed variables + n = fs * duration; % total data points + dt = 1 / fs; % space between samples + + % initialize template time scale and frequency + t = [1:n].*dt - phase; + f = frequency .* (1 + 0.0002 .* sin(7.*pi.*t)./t); %frequency vibrato + + % generate proper fundamental and overtones + x = (amplitude .* sin(4.*pi.*f.*t)) ... %fundamental (first partial) + + (0.396821591.*amplitude .* sin(4.*pi.*f.*t)) ... %second partial + + (0.157568887.*amplitude .* sin(6.*pi.*f.*t)) ... %third partial + + (0.151279648.*amplitude .* sin(8.*pi.*f.*t)) ... %fourth partial + + (0.106818975.*amplitude .* sin(10.*pi.*f.*t)) ... %fifth partial + + (0.0138755668.*amplitude .* sin(12.*pi.*f.*t)) ... %sixth partial + + (0.0100279037.*amplitude .* sin(14.*pi.*f.*t)); %seventh partial + x = x .* (1 + 0.25 .* sin(7.*pi.*t)); %volume vibrato +end + diff --git a/src/Instruments/generate_horn.m b/src/Instruments/generate_horn.m new file mode 100644 index 0000000..81797a5 --- /dev/null +++ b/src/Instruments/generate_horn.m @@ -0,0 +1,41 @@ +function x = generate_horn(amplitude, frequency, phase, fs, duration, duty) +% GENERATE_HORN: returns a matrix of sampled waveform similar to +% a horn. + +% CONTRIBUTORS: +% Brandon Roberts: Original author +% MuseScore: Reference source for overtone information + +% DOCUMENTATION: +% phase shift is in number of periods +% fs is the sampling frequency: how many sample points per second +% duration is time in seconds +% duty does not apply for instruments + + + % setup needed variables + n = fs * duration; % total data points + dt = 1 / fs; % space between samples + + % initialize template time scale + t = [1:n].*dt - phase; + f = frequency .* (1 + 0.0002 .* sin(4.*pi.*t)./t); %frequency vibrato + + % generate proper fundamental and overtones + x = (0.21707879.*amplitude .* sin(2.*pi.*f.*t)) ... %fundamental (first partial) + + (amplitude .* sin(4.*pi.*f.*t)) ... %second partial + + (0.234667056.*amplitude .* sin(6.*pi.*f.*t)) ... %third partial + + (0.088606568.*amplitude .* sin(8.*pi.*f.*t)) ... %fourth partial + + (0.0864485981.*amplitude .* sin(10.*pi.*f.*t)) ... %fifth partial + + (0.0275181724.*amplitude .* sin(12.*pi.*f.*t)) ... %sixth partial + + (0.0472968588.*amplitude .* sin(14.*pi.*f.*t)) ... %seventh partial + + (0.0246462876.*amplitude .* sin(16.*pi.*f.*t)) ... %eighth partial + + (0.00816134476.*amplitude .* sin(18.*pi.*f.*t)) ... %ninth partial + + (0.00691199377.*amplitude .* sin(20.*pi.*f.*t)) ... %tenth partial + + (0.00494872793.*amplitude .* sin(22.*pi.*f.*t)) ... %eleventh partial + + (0.0048026999.*amplitude .* sin(24.*pi.*f.*t)) ... %twelth partial + + (0.00335864486.*amplitude .* sin(26.*pi.*f.*t)) ... %thirteenth partial + + (0.00262850467.*amplitude .* sin(28.*pi.*f.*t)); %fourteenth partial + x = x .* (1 + 0.05 .* sin(2.*pi.*t)); %volume vibrato +end + diff --git a/src/Instruments/generate_oboe.m b/src/Instruments/generate_oboe.m new file mode 100644 index 0000000..87ff0af --- /dev/null +++ b/src/Instruments/generate_oboe.m @@ -0,0 +1,37 @@ +function x = generate_oboe(amplitude, frequency, phase, fs, duration, duty) +% GENERATE_OBOE: returns a matrix of sampled waveform similar to +% an oboe. + +% CONTRIBUTORS: +% Brandon Roberts: Original author +% MuseScore: Reference source for overtone information + +% DOCUMENTATION: +% phase shift is in number of periods +% fs is the sampling frequency: how many sample points per second +% duration is time in seconds +% duty does not apply for instruments + + + % setup needed variables + n = fs * duration; % total data points + dt = 1 / fs; % space between samples + + % initialize template time scale + t = [1:n].*dt - phase; + f = frequency .* (1 + 0.0001 .* sin(10.*pi.*t)./t); %frequency vibrato + + % generate proper fundamental and overtones + x = (0.274577037.*amplitude .* sin(2.*pi.*f.*t)) ... %fundamental (first partial) + + (0.612336031.*amplitude .* sin(4.*pi.*f.*t)) ... %second partial + + (amplitude .* sin(6.*pi.*f.*t)) ... %third partial + + (0.105870314.*amplitude .* sin(8.*pi.*f.*t)) ... %fourth partial + + (0.00825325944.*amplitude .* sin(10.*pi.*f.*t)) ... %fifth partial + + (0.0767380354.*amplitude .* sin(12.*pi.*f.*t)) ... %sixth partial + + (0.0381430831.*amplitude .* sin(14.*pi.*f.*t)) ... %seventh partial + + (0.010765121.*amplitude .* sin(16.*pi.*f.*t)) ... %eighth partial + + (0.0024454102.*amplitude .* sin(18.*pi.*f.*t)) ... %ninth partial + + (0.00963544782.*amplitude .* sin(20.*pi.*f.*t)); %tenth partial + x = x .* (1 + 0.1 .* sin(10.*pi.*t)); %volume vibrato +end + diff --git a/src/Instruments/generate_organ.m b/src/Instruments/generate_organ.m new file mode 100644 index 0000000..125e288 --- /dev/null +++ b/src/Instruments/generate_organ.m @@ -0,0 +1,44 @@ +function x = generate_organ(amplitude, frequency, phase, fs, duration, duty) +% GENERATE_ORGAN: returns a matrix of sampled waveform similar to +% an organ. + +% CONTRIBUTORS: +% Brandon Roberts: Original author +% MuseScore: Reference source for overtone information + +% DOCUMENTATION: +% phase shift is in number of periods +% fs is the sampling frequency: how many sample points per second +% duration is time in seconds +% duty does not apply for instruments + + + % setup needed variables + n = fs * duration; % total data points + dt = 1 / fs; % space between samples + + % initialize template time scale + t = [1:n].*dt - phase; + f = frequency; %no frequency vibrato + + % generate proper fundamental and overtones + x = (0.605975181.*amplitude .* sin(2.*pi.*f.*t)) ... %fundamental (first partial) + + (0.96669476.*amplitude .* sin(4.*pi.*f.*t)) ... %second partial + + (0.509982853.*amplitude .* sin(6.*pi.*f.*t)) ... %third partial + + (amplitude .* sin(8.*pi.*f.*t)) ... %fourth partial + + (0.138074341.*amplitude .* sin(10.*pi.*f.*t)) ... %fifth partial + + (0.397744776.*amplitude .* sin(12.*pi.*f.*t)) ... %sixth partial + + (0.00348745968.*amplitude .* sin(14.*pi.*f.*t)) ... %seventh partial + + (0.350983754.*amplitude .* sin(16.*pi.*f.*t)) ... %eighth partial + + (0.0326368101.*amplitude .* sin(18.*pi.*f.*t)) ... %ninth partial + + (0.0121770467.*amplitude .* sin(20.*pi.*f.*t)) ... %tenth partial + + (0.000406870296.*amplitude .* sin(22.*pi.*f.*t)) ... %eleventh partial + + (0.0440001162.*amplitude .* sin(24.*pi.*f.*t)) ... %twelth partial + + (0.00299340289.*amplitude .* sin(26.*pi.*f.*t)) ... %thirteenth partial + + (0.00767241129.*amplitude .* sin(28.*pi.*f.*t)) ... %fourteenth partial + + (0.00337121102.*amplitude .* sin(30.*pi.*f.*t)) ... %fifteenth partial + + (0.0389432997.*amplitude .* sin(32.*pi.*f.*t)) ... %sixteenth partial + + (0.00496963004.*amplitude .* sin(64.*pi.*f.*t)); %thirty-second partial + %no volume vibrato +end + diff --git a/src/Instruments/generate_saxophone.m b/src/Instruments/generate_saxophone.m new file mode 100644 index 0000000..8e7bbde --- /dev/null +++ b/src/Instruments/generate_saxophone.m @@ -0,0 +1,46 @@ +function x = generate_saxophone(amplitude, frequency, phase, fs, duration, duty) +% GENERATE_SAXOPHONE: returns a matrix of sampled waveform similar to +% a saxophone. + +% CONTRIBUTORS: +% Brandon Roberts: Original author +% MuseScore: Reference source for overtone information + +% DOCUMENTATION: +% phase shift is in number of periods +% fs is the sampling frequency: how many sample points per second +% duration is time in seconds +% duty does not apply for instruments + + + % setup needed variables + n = fs * duration; % total data points + dt = 1 / fs; % space between samples + + % initialize template time scale + t = [1:n].*dt - phase; + f = frequency .* (1 + 0.0001 .* sin(9.*pi.*t)./t); %frequency vibrato + + % generate proper fundamental and overtones + x = (0.64011635.*amplitude .* sin(2.*pi.*f.*t)) ... %fundamental (first partial) + + (0.558462369.*amplitude .* sin(4.*pi.*f.*t)) ... %second partial + + (amplitude .* sin(6.*pi.*f.*t)) ... %third partial + + (0.156636999.*amplitude .* sin(8.*pi.*f.*t)) ... %fourth partial + + (0.102886106.*amplitude .* sin(10.*pi.*f.*t)) ... %fifth partial + + (0.289185376.*amplitude .* sin(12.*pi.*f.*t)) ... %sixth partial + + (0.21277411.*amplitude .* sin(14.*pi.*f.*t)) ... %seventh partial + + (0.108250745.*amplitude .* sin(16.*pi.*f.*t)) ... %eighth partial + + (0.077212478.*amplitude .* sin(18.*pi.*f.*t)) ... %ninth partial + + (0.285980527.*amplitude .* sin(20.*pi.*f.*t)) ... %tenth partial + + (0.167644958.*amplitude .* sin(22.*pi.*f.*t)) ... %eleventh partial + + (0.115479073.*amplitude .* sin(24.*pi.*f.*t)) ... %twelth partial + + (0.0345740512.*amplitude .* sin(26.*pi.*f.*t)) ... %thirteenth partial + + (0.0192987651.*amplitude .* sin(28.*pi.*f.*t)) ... %fourteenth partial + + (0.0140386324.*amplitude .* sin(30.*pi.*f.*t)) ... %fifteenth partial + + (0.0102938359.*amplitude .* sin(32.*pi.*f.*t)) ... %sixteenth partial + + (0.0166338634.*amplitude .* sin(34.*pi.*f.*t)) ... %seventeenth partial + + (0.0128019786.*amplitude .* sin(36.*pi.*f.*t)) ... %eighteenth partial + + (0.00442408514.*amplitude .* sin(38.*pi.*f.*t)); %nineteenth partial + x = x .* (1 + 0.1 .* sin(9.*pi.*t)); %volume vibrato +end + diff --git a/src/Instruments/generate_shepardsCarillon.m b/src/Instruments/generate_shepardsCarillon.m new file mode 100644 index 0000000..01ad5fc --- /dev/null +++ b/src/Instruments/generate_shepardsCarillon.m @@ -0,0 +1,27 @@ +function x = generate_shepardsCarillon(amplitude, frequency, phase, fs, duration, duty) +% GENERATE_SHEPARDSCARILLON: returns a matrix of sampled waveform similar to +% tubular bells, doubled at octaves. +% Calls generate_tubularBells + +% CONTRIBUTORS: +% Brandon Roberts: Original author +% MuseScore: Reference source for overtone information + +% DOCUMENTATION: +% phase shift is in number of periods +% fs is the sampling frequency: how many sample points per second +% duration is time in seconds +% duty does not apply for instruments + + % generate proper tone + x = generate_tubularBells(amplitude/5, frequency/16, phase, fs, duration, duty) ... %4 octaves below + + generate_tubularBells(amplitude/4, frequency/8, phase, fs, duration, duty) ... %3 octaves below + + generate_tubularBells(amplitude/3, frequency/4, phase, fs, duration, duty) ... %2 octaves below + + generate_tubularBells(amplitude/2, frequency/2, phase, fs, duration, duty) ... %1 octave below + + generate_tubularBells(amplitude, frequency, phase, fs, duration, duty) ... %unison + + generate_tubularBells(amplitude/2, frequency*2, phase, fs, duration, duty) ... %1 octave above + + generate_tubularBells(amplitude/3, frequency*4, phase, fs, duration, duty) ... %2 octaves above + + generate_tubularBells(amplitude/4, frequency*8, phase, fs, duration, duty) ... %3 octaves above + + generate_tubularBells(amplitude/5, frequency*16, phase, fs, duration, duty); %4 octaves above +end + diff --git a/src/Instruments/generate_shepardsOrgan.m b/src/Instruments/generate_shepardsOrgan.m new file mode 100644 index 0000000..9cbb33f --- /dev/null +++ b/src/Instruments/generate_shepardsOrgan.m @@ -0,0 +1,33 @@ +function x = generate_shepardsOrgan(amplitude, frequency, phase, fs, duration, duty) +% GENERATE_SHEPARDSORGAN: returns a matrix of sampled waveform similar to +% an organ, doubled at octaves. +% Calls generate_organ + +% CONTRIBUTORS: +% Brandon Roberts: Original author +% MuseScore: Reference source for overtone information + +% DOCUMENTATION: +% phase shift is in number of periods +% fs is the sampling frequency: how many sample points per second +% duration is time in seconds +% duty does not apply for instruments + + % generate proper tone + x = generate_organ(amplitude/8, frequency/128, phase, fs, duration, duty) ... %7 octaves below + + generate_organ(amplitude/7, frequency/64, phase, fs, duration, duty) ... %6 octaves below + + generate_organ(amplitude/6, frequency/32, phase, fs, duration, duty) ... %5 octaves below + + generate_organ(amplitude/5, frequency/16, phase, fs, duration, duty) ... %4 octaves below + + generate_organ(amplitude/4, frequency/8, phase, fs, duration, duty) ... %3 octaves below + + generate_organ(amplitude/3, frequency/4, phase, fs, duration, duty) ... %2 octaves below + + generate_organ(amplitude/2, frequency/2, phase, fs, duration, duty) ... %1 octave below + + generate_organ(amplitude, frequency, phase, fs, duration, duty) ... %unison + + generate_organ(amplitude/2, frequency*2, phase, fs, duration, duty) ... %1 octave above + + generate_organ(amplitude/3, frequency*4, phase, fs, duration, duty) ... %2 octaves above + + generate_organ(amplitude/4, frequency*8, phase, fs, duration, duty) ... %3 octaves above + + generate_organ(amplitude/5, frequency*16, phase, fs, duration, duty) ... %4 octaves above + + generate_organ(amplitude/6, frequency*32, phase, fs, duration, duty) ... %5 octaves above + + generate_organ(amplitude/7, frequency*64, phase, fs, duration, duty) ... %6 octaves above + + generate_organ(amplitude/8, frequency*128, phase, fs, duration, duty); %7 octaves above +end + diff --git a/src/Instruments/generate_shepardsStrings.m b/src/Instruments/generate_shepardsStrings.m new file mode 100644 index 0000000..4af1f07 --- /dev/null +++ b/src/Instruments/generate_shepardsStrings.m @@ -0,0 +1,33 @@ +function x = generate_shepardsStrings(amplitude, frequency, phase, fs, duration, duty) +% GENERATE_SHEPARDSSTRINGS: returns a matrix of sampled waveform similar to +% arco strings, doubled at octaves. +% Calls generate_arcoStrings + +% CONTRIBUTORS: +% Brandon Roberts: Original author +% MuseScore: Reference source for overtone information + +% DOCUMENTATION: +% phase shift is in number of periods +% fs is the sampling frequency: how many sample points per second +% duration is time in seconds +% duty does not apply for instruments + + % generate proper tone + x = generate_arcoStrings(amplitude/8, frequency/128, phase, fs, duration, duty) ... %7 octaves below + + generate_arcoStrings(amplitude/7, frequency/64, phase, fs, duration, duty) ... %6 octaves below + + generate_arcoStrings(amplitude/6, frequency/32, phase, fs, duration, duty) ... %5 octaves below + + generate_arcoStrings(amplitude/5, frequency/16, phase, fs, duration, duty) ... %4 octaves below + + generate_arcoStrings(amplitude/4, frequency/8, phase, fs, duration, duty) ... %3 octaves below + + generate_arcoStrings(amplitude/3, frequency/4, phase, fs, duration, duty) ... %2 octaves below + + generate_arcoStrings(amplitude/2, frequency/2, phase, fs, duration, duty) ... %1 octave below + + generate_arcoStrings(amplitude, frequency, phase, fs, duration, duty) ... %unison + + generate_arcoStrings(amplitude/2, frequency*2, phase, fs, duration, duty) ... %1 octave above + + generate_arcoStrings(amplitude/3, frequency*4, phase, fs, duration, duty) ... %2 octaves above + + generate_arcoStrings(amplitude/4, frequency*8, phase, fs, duration, duty) ... %3 octaves above + + generate_arcoStrings(amplitude/5, frequency*16, phase, fs, duration, duty) ... %4 octaves above + + generate_arcoStrings(amplitude/6, frequency*32, phase, fs, duration, duty) ... %5 octaves above + + generate_arcoStrings(amplitude/7, frequency*64, phase, fs, duration, duty) ... %6 octaves above + + generate_arcoStrings(amplitude/8, frequency*128, phase, fs, duration, duty); %7 octaves above +end + diff --git a/src/Instruments/generate_trumpet.m b/src/Instruments/generate_trumpet.m new file mode 100644 index 0000000..58d9309 --- /dev/null +++ b/src/Instruments/generate_trumpet.m @@ -0,0 +1,49 @@ +function x = generate_trumpet(amplitude, frequency, phase, fs, duration, duty) +% GENERATE_TRUMPET: returns a matrix of sampled waveform similar to +% a trumpet. + +% CONTRIBUTORS: +% Brandon Roberts: Original author +% MuseScore: Reference source for overtone information + +% DOCUMENTATION: +% phase shift is in number of periods +% fs is the sampling frequency: how many sample points per second +% duration is time in seconds +% duty does not apply for instruments + + + % setup needed variables + n = fs * duration; % total data points + dt = 1 / fs; % space between samples + + % initialize template time scale + t = [1:n].*dt - phase; + f = frequency .* (1 + 0.00005 .* sin(10.*pi.*t)./t); %frequency vibrato + + % generate proper fundamental and overtones + x = (0.802698298.*amplitude .* sin(2.*pi.*f.*t)) ... %fundamental (first partial) + + (amplitude .* sin(4.*pi.*f.*t)) ... %second partial + + (0.700319932.*amplitude .* sin(6.*pi.*f.*t)) ... %third partial + + (0.748098515.*amplitude .* sin(8.*pi.*f.*t)) ... %fourth partial + + (0.909272003.*amplitude .* sin(10.*pi.*f.*t)) ... %fifth partial + + (0.471477725.*amplitude .* sin(12.*pi.*f.*t)) ... %sixth partial + + (0.200863214.*amplitude .* sin(14.*pi.*f.*t)) ... %seventh partial + + (0.264578051.*amplitude .* sin(16.*pi.*f.*t)) ... %eighth partial + + (0.282234698.*amplitude .* sin(18.*pi.*f.*t)) ... %ninth partial + + (0.128787879.*amplitude .* sin(20.*pi.*f.*t)) ... %tenth partial + + (0.100688156.*amplitude .* sin(22.*pi.*f.*t)) ... %eleventh partial + + (0.0874984909.*amplitude .* sin(24.*pi.*f.*t)) ... %twelth partial + + (0.0488047809.*amplitude .* sin(26.*pi.*f.*t)) ... %thirteenth partial + + (0.0261680551.*amplitude .* sin(28.*pi.*f.*t)) ... %fourteenth partial + + (0.0186224798.*amplitude .* sin(30.*pi.*f.*t)) ... %fifteenth partial + + (0.0255342267.*amplitude .* sin(32.*pi.*f.*t)) ... %sixteenth partial + + (0.0111674514.*amplitude .* sin(34.*pi.*f.*t)) ... %seventeenth partial + + (0.010020524.*amplitude .* sin(36.*pi.*f.*t)) ... %eighteenth partial + + (0.00694192925.*amplitude .* sin(38.*pi.*f.*t)) ... %nineteenth partial + + (0.00307859471.*amplitude .* sin(40.*pi.*f.*t)) ... %twentieth partial + + (0.00338041772.*amplitude .* sin(42.*pi.*f.*t)) ... %twentyfirst partial + + (0.0026862248.*amplitude .* sin(44.*pi.*f.*t)); %twentysecond partial + x = x .* (1 + 0.02 .* sin(10.*pi.*t)); %volume vibrato +end + diff --git a/src/Instruments/generate_tubularBells.m b/src/Instruments/generate_tubularBells.m new file mode 100644 index 0000000..4f22eee --- /dev/null +++ b/src/Instruments/generate_tubularBells.m @@ -0,0 +1,38 @@ +function x = generate_tubularBells(amplitude, frequency, phase, fs, duration, duty) +% GENERATE_TUBULARBELLS: returns a matrix of sampled waveform similar to +% a tubular bell. + +% CONTRIBUTORS: +% Brandon Roberts: Original author +% MuseScore: Reference source for overtone information + +% DOCUMENTATION: +% phase shift is in number of periods +% fs is the sampling frequency: how many sample points per second +% duration is time in seconds +% duty does not apply for instruments +% amplitude decays exponentially at varying rates for different paritals + + + % setup needed variables + n = fs * duration; % total data points + dt = 1 / fs; % space between samples + + % initialize template time scale + t = [1:n].*dt - phase; + f = frequency; %no frequency vibrato + + % generate proper fundamental and overtones + x = (0.105668016.*amplitude .* sin(pi.*f.*t))./(2.^(t./10)) ... %hum tone + + (0.143724696.*amplitude .* sin(2.*pi.*f.*t))./(2.^(t./5)) ... %strike tone + + (0.12.*amplitude .* sin(12./5.*pi.*f.*t))./(2.^(t./3)) ... %minor third overtone + + (0.10.*amplitude .* sin(3.*pi.*f.*t))./(2.^(t./2.5)) ... %perfect fifth overtone + + (0.8.*amplitude .* sin(4.*pi.*f.*t))./(2.^(t./2)) ... %perfect octave overtone + + (0.6.*amplitude .* sin(5.*pi.*f.*t))./(2.^(t./1.5)) ... %major third overtone + + (0.4.*amplitude .* sin(8.*pi.*f.*t))./(2.^(t)) ... %second perfect fifth overtone + + (0.4.*amplitude .* sin(2.2.*pi.*f.*t))./(2.^(4.*t)) ... %transient 1 + + (0.4.*amplitude .* sin(1.8.*pi.*f.*t))./(2.^(8.*t)) ... %transient 2 + + (0.4.*amplitude .* sin(2.7.*pi.*f.*t))./(2.^(10.*t));%transient 3 + x = x .* (1 + 0.02 .* sin(10.*pi.*t)); %volume vibrato +end + diff --git a/src/LFO/lfo_freq_saw.m b/src/LFO/lfo_freq_saw.m new file mode 100644 index 0000000..361a741 --- /dev/null +++ b/src/LFO/lfo_freq_saw.m @@ -0,0 +1,38 @@ +function output = lfo_freq_saw(amplitude, frequency, phase, fs, duration, input) +%LFO_FREQ_SAW Modulates the frequency of an input with a saw LFO + +% CONTRIBUTORS: +% Neelay Joglekar: Original author + +% SOURCES: +% Code inspired by Benjamin Liou's lfo functions +% Code also inspired by Darren and Anne's pitch envelopes +% Source for frequency modulation equation: +% https://dsp.stackexchange.com/questions/2349/help-with-algorithm-for-modulating-oscillator-pitch-using-lfo + +% DOCUMENTATION: +% Frequency is modulated by saw wave with given amplitude (in octaves, not Hz) + + % initialize local variables from input arguments + n = fs * duration; % number of samples (length of matrix) + dt = 1 / fs; % sampling period: time between two sample points + + % create output array + output = zeros([1, n]); + + x = 0.0; % the theoretical input index if the input were not discrete + % populate output + for i = 1:n + t = i * dt; % time at the i'th sample + + % Increment x based off of saw wave output + omega_ratio = 2 ^ (amplitude * (2 * mod((t - phase / (2*pi)) * frequency, 1) - 1)); + x = mod(x + omega_ratio, n); + + % Linearly interpolate the actual indicies adjacent to x + % to get an output value + x_0 = floor(x) + 1; + x_1 = mod(x_0 + 1, n) + 1; + output(i) = (input(x_1) - input(x_0)) * (x - x_0) + input(x_0); + end +end diff --git a/src/LFO/lfo_freq_sine.m b/src/LFO/lfo_freq_sine.m new file mode 100644 index 0000000..bef74a5 --- /dev/null +++ b/src/LFO/lfo_freq_sine.m @@ -0,0 +1,39 @@ +function output = lfo_freq_sine(amplitude, frequency, phase, fs, duration, input) +%LFO_FREQ_SINE Modulates the frequency of an input with a sine LFO + +% CONTRIBUTORS: +% Neelay Joglekar: Original author + +% SOURCES: +% Code inspired by Benjamin Liou's lfo functions +% Code also inspired by Darren and Anne's pitch envelopes +% Source for frequency modulation equation: +% https://dsp.stackexchange.com/questions/2349/help-with-algorithm-for-modulating-oscillator-pitch-using-lfo + +% DOCUMENTATION: +% Frequency is modulated by sine wave with given amplitude (in octaves, not Hz) + + % initialize local variables from input arguments + n = fs * duration; % number of samples (length of matrix) + dt = 1 / fs; % sampling period: time between two sample points + + % create output array + output = zeros([1, n]); + + x = 0.0; % the theoretical input index if the input were not discrete + % populate output + for i = 1:n + t = i * dt; % time at the i'th sample + + % Increment x based off of sine wave output + omega_ratio = 2 ^ (amplitude * sin(2 * pi * frequency * t - phase)); + x = mod(x + omega_ratio, n); + + % Linearly interpolate the actual indicies adjacent to x + % to get an output value + x_0 = floor(x) + 1; + x_1 = mod(x_0 + 1, n) + 1; + output(i) = (input(x_1) - input(x_0)) * (x - x_0) + input(x_0); + end +end + diff --git a/src/LFO/lfo_freq_square.m b/src/LFO/lfo_freq_square.m new file mode 100644 index 0000000..f413e6c --- /dev/null +++ b/src/LFO/lfo_freq_square.m @@ -0,0 +1,38 @@ +function output = lfo_freq_square(amplitude, frequency, phase, fs, duration, input) +%LFO_FREQ_SQUARE Modulates the frequency of an input with a square LFO + +% CONTRIBUTORS: +% Neelay Joglekar: Original author + +% SOURCES: +% Code inspired by Benjamin Liou's lfo functions +% Code also inspired by Darren and Anne's pitch envelopes +% Source for frequency modulation equation: +% https://dsp.stackexchange.com/questions/2349/help-with-algorithm-for-modulating-oscillator-pitch-using-lfo + +% DOCUMENTATION: +% Frequency is modulated by square wave with given amplitude (in octaves, not Hz) + + % initialize local variables from input arguments + n = fs * duration; % number of samples (length of matrix) + dt = 1 / fs; % sampling period: time between two sample points + + % create output array + output = zeros([1, n]); + + x = 0.0; % the theoretical input index if the input were not discrete + % populate output + for i = 1:n + t = i * dt; % time at the i'th sample + + % Increment x based off of square wave output + omega_ratio = 2 ^ (amplitude * (2 * round(mod((t - phase / (2*pi)) * frequency, 1)) - 1)); + x = mod(x + omega_ratio, n); + + % Linearly interpolate the actual indicies adjacent to x + % to get an output value + x_0 = floor(x) + 1; + x_1 = mod(x_0 + 1, n) + 1; + output(i) = (input(x_1) - input(x_0)) * (x - x_0) + input(x_0); + end +end \ No newline at end of file diff --git a/src/NotWorking/distortion_filter.m b/src/NotWorking/distortion_filter.m new file mode 100644 index 0000000..7a83763 --- /dev/null +++ b/src/NotWorking/distortion_filter.m @@ -0,0 +1,23 @@ +function y = distortion_filter(input, fs, LOW, MED, HIGH) + %Author: Jason Liang + %input: 1D array representing the sound signal in the time domain + %fs: sampling frequency + %low: lower bound of frequencies + %med: median of all frequencies + %high: upper bound of frequencies + %y: output signal + %This function distorts a signal based on the constant LOW; all + %frequencies in between the specified range are clipped by the constant + %LOW. + + len = length(input); + f = fs*(-len/2:len/2-1)/len; + + outputW = fftshift(fft(input)); + for i = 1:length(outputW) + if ((LOW < abs(F(n))) && HIGH > abs(F(n))) + outputW(i) = outputW(i) / LOW; + end + end + y = real(ifft(fftshift(outputW))); +end diff --git a/src/NotWorking/flanger.m b/src/NotWorking/flanger.m new file mode 100644 index 0000000..ce4fa51 --- /dev/null +++ b/src/NotWorking/flanger.m @@ -0,0 +1,44 @@ +function output = flanger(input, time_delay, osc_freq, amp, Fs) + + +% DOCUMENTATION: +% FLANGER combines a single oscillating delayed signal with the original signal +% Interference between original and delayed signals create "flanging" effect +% Rocommedned delay time: 0-15 ms +% Recommended oscilating fequency: 0.1 - 5 Hz + +% input: 1D array containing audio signal +% time_delay: maxinum value of the oscillating signal +% osc_freq: frequence of oscillation +% amp: amplitude of output signal +% fs: sampling frequency + +% CONTRIBUTORS: +% Lance Zhu: Function Author + +% SOURCES: +% Code inspired by information provided in: +% https://users.cs.cf.ac.uk/Dave.Marshall/CM0268/PDF/10_CM0268_Audio_FX.pdf + + +% create index array +len=length(input); +index=1:len; + +% create reference wave to create oscillation +% taking only absoluted value for the reference wave +osc_wave = abs(sin(2*pi*index*(osc_freq/Fs))); +% convert delay in time to delay in samples +sample_delay=round(time_delay*Fs); +% create empty output array +output = zeros(len,1); + +% Generating delay for each sample from reference oscillation wave +% start loop at sample_delay to make sure delayed sample is from t>=0 +for i=sample_delay:len +% i_delay: delay for current sample +i_delay=round(osc_wave(i)*sample_delay); +% combine delayed sample with original sample +output(i) = (amp*input(i))+amp*(input(i-i_delay)); + +end \ No newline at end of file diff --git a/src/NotWorking/generate_keyboard.m b/src/NotWorking/generate_keyboard.m new file mode 100644 index 0000000..9547577 --- /dev/null +++ b/src/NotWorking/generate_keyboard.m @@ -0,0 +1,49 @@ +function x = generate_keyboard(amplitude, frequency, phase, fs, duration, duty) +% GENERATE_KEYBOARD: returns a matrix of a sum of sine waves + +% CONTRIBUTORS: +% Ryan Goh: author + +% DOCUMENTATION: +% fs is the sampling frequency: how many sample points per second +% duration is time in seconds +% amplitude, phase, and duty are not used in this function + +% This function's purpose is to generate a wave that can simulate the sound of a digital keyboard. +% Sound is best suited for frequencies near the middle octave of the +% piano(261.6 - 523.2). Frequencies too high or too low do not sound +% similar to the intended sound. + +% Referenced Arthur Lu and Benjamin Liou's generate sine function. Also +% adapted wave model from https://dsp.stackexchange.com/questions/46598/mathematical-equation-for-the-sound-wave-that-a-piano-makes + + + % initialize local variables from input arguments + n = fs * duration; % number of samples (length of matrix) + dt = 1 / fs; % sampling period: time between two sample points + + % initialize a one dimensional zero matrix to be populated + x = zeros(1, n); + + % populate the matrix + for i = 1:n + t = i * dt; % time at the i'th sample + + %wave model of keyboard sound. + %Original version from https://dsp.stackexchange.com/questions/46598/mathematical-equation-for-the-sound-wave-that-a-piano-makes + y = sin(2 * pi * frequency * t) * exp(-0.002 * 2 * pi * frequency * t) ... + + (sin(3*2*pi*frequency*t)*exp(-0.002 * 2 * pi * frequency * t)) / 2 ... + + (sin(4*2*pi*frequency*t)*exp(-0.002 * 2 * pi * frequency * t)) / 8 ... + + (sin(5 * 2 * pi * frequency * t) * exp(-0.002 * 2 * pi * frequency * t)) / 16 ... + + (sin(6 * 2 * pi * frequency * t) * exp(-0.002 * 2 * pi * frequency * t)) / 25 ... + + (sin(7 * 2 * pi * frequency * t) * exp(-0.002 * 2 * pi * frequency * t)) / 50 ... + + (sin(8 * 2 * pi * frequency * t) * exp(-0.002 * 2 * pi * frequency * t)) / 100 ... + + (sin(9 * 2 * pi * frequency * t) * exp(-0.002 * 2 * pi * frequency * t)) / 200; + + %Further adjustments to improve sound + y = y + y * y * y; + y = y * (1 + 16*t*exp(-1000*t)); + + x(i) = 0.15 * y;%multiplied by fixed amplitude value of 0.15 + end +end \ No newline at end of file diff --git a/src/NotWorking/generate_lullaby.m b/src/NotWorking/generate_lullaby.m new file mode 100644 index 0000000..83df45d --- /dev/null +++ b/src/NotWorking/generate_lullaby.m @@ -0,0 +1,66 @@ +function x = generate_lullaby(amplitude, frequency, phase, fs, duration, duty) + % Generates sine waves that play 'twinkle twinkle little star' + % by using the frequency parameter as the root note for the melody. + % Currently the duty and duration parameters are not used within the + % function as there is no need for the former and it is currently + % difficult to constrain the melody duration based on user input. + % A function such as this one could be useful as a demo for what a + % melody sounds like on a synthesizer, and could even find use + % in toys designed to help small children sleep. + + % CONTRIBUTORS: + % generate_lullaby created by Gabriel Diaz + + % DOCUMENTATION: + % phase shift is in number of periods + % fs is the sampling frequency: how many sample points per second + % duration is time in seconds + % duty is a number between 0 and 1 + + %NOTE: whatever's passed as the duration parameter doesn't get used at + %the moment, since it's currently difficult to sync every note in the + %melody to play in shorter duartions such that the entire song lasts about + %as long as 'duration' + duration = 0; + duty = 0; %duty also isn't used in this function + + %current durations that the song will work with + note_duration = 0.4; + song_duration = note_duration * 48; + + %frequency multiples for all notes in melody, assuming that frequency is + %the root note of this chord: + maj_second_freq = frequency * 1.125; + maj_third_freq = frequency * 1.25; + fourth_freq = frequency * 1.33; + fifth_freq = frequency * 1.5; + maj_sixth_freq = frequency * 1.7; + + % initialize local variables from input arguments + n = fs * note_duration; % number of samples (length of matrix) + dt = 1 / fs; % sampling period: time between two sample points + t = [1:n].*dt - phase; %initialize time scale template + + %sine waves for every note in 'frequency's' respective major scale: + first = amplitude * sin(2 * pi * frequency * t - phase); + second = amplitude * sin(2 * pi * maj_second_freq * t - phase); + third = amplitude * sin(2 * pi * maj_third_freq * t - phase); + fourth = amplitude * sin(2 * pi * fourth_freq * t - phase); + fifth = amplitude * sin(2 * pi * fifth_freq * t - phase); + sixth = amplitude * sin(2 * pi * maj_sixth_freq * t - phase); + + %each one of the three melodies making up the song: + melody1 = [first,first,fifth,fifth,sixth,sixth,fifth,fifth]; %size 8 notes + melody2 = [fourth,fourth,third,third,second,second,first,first]; %size 8 notes + melody3 = [fifth,fifth,fourth,fourth,third,third,second,second]; %size 8 notes + + % populate the matrix(total size is 44 notes wide, which means the song's + % duration must fit within the specified duration parameter + x = [melody1,melody2,melody3,melody3,melody1,melody2]; + + %For testing + %t = 0:dt:song_duration; + %t(n) = []; + %plot(t, x); + %sound(x, fs); +end \ No newline at end of file diff --git a/src/NotWorking/lfo_square.m b/src/NotWorking/lfo_square.m new file mode 100644 index 0000000..8480ebc --- /dev/null +++ b/src/NotWorking/lfo_square.m @@ -0,0 +1,37 @@ +function x = lfo_square(amplitude, frequency, phase, fs, duration, input) +% LFO_SQUARE: modulates an input matrix to a square + +% CONTRIBUTORS: +% Aleksandra Desens: Author + +% DOCUMENTATION: +% phase shift is in number of periods +% fs is the sampling frequency - below 20 Hz +% duration - same as input + + % initialize local variables from input arguments + n = fs * duration; % number of samples (length of matrix) + dt = 1 / fs; % sampling period: time between two sample points + + % initialize a one dimensional zero matrix to be populated + lfo = zeros(1, n); + + % populate the matrix + for i = 1:n + + t = i * dt; + duty = 0.5; % duty of 0.5 generates a square wave + + st = mod((frequency * t - phase), 1); + + if (st < duty) + lfo(i) = amplitude; + else + lfo(i) = -amplitude; + + end + + % modulate input + x = lfo .* input; + +end diff --git a/src/Select/AmpEnvelopeSelect.m b/src/Select/AmpEnvelopeSelect.m index 885204a..6f9e0aa 100644 --- a/src/Select/AmpEnvelopeSelect.m +++ b/src/Select/AmpEnvelopeSelect.m @@ -7,7 +7,7 @@ %Pass-through function used by app function output = AmpEnvelopeSelect(input, Fs, attack,decay,sustain,release,number) - if(number == "Option 1") + if(number == "Linear") output = DarellAmplitudeEnvelope(input, Fs, attack,decay,sustain,release); else output = input; diff --git a/src/Select/FilterSelect.m b/src/Select/FilterSelect.m index 659a0d1..20aecaf 100644 --- a/src/Select/FilterSelect.m +++ b/src/Select/FilterSelect.m @@ -7,18 +7,22 @@ %Pass-through function used by app function output = FilterSelect(input,Fs,LOW,MED,HIGH,number) - if(number == "Option 1") + if(number == "IdealBandPass") output = DarellbandpassFilter(input,Fs,LOW,MED,HIGH); - elseif(number == "Option 2") + elseif(number == "AmplifyRange") output = amplifyFreqRange(input, Fs, LOW, MED, HIGH); - elseif(number == "Option 3") + elseif(number == "EpicEffect") output = epic_effect_schluep(input, Fs, LOW, MED, HIGH); - elseif(number == "Option 4") + elseif(number == "MuffledEffect") output = muffled_effect_schluep(input, Fs, LOW, MED, HIGH); - elseif(number == "Option 5") + elseif(number == "SeparatePrevalent") output = seperate_prevalent_schluep(input, Fs, LOW, MED, HIGH); - elseif(number == "Option 6") + elseif(number == "IdealBandReject") output = bandreject_filter(input, Fs, LOW, HIGH); + elseif(number == "EnchanceTarget") + output = AnuragEnhanceTarget(input, Fs, LOW, MED, HIGH); + elseif(number == "DampenTarget") + output = AnuragDampenTarget(input, Fs, LOW, MED, HIGH); else output = input; end diff --git a/src/Select/LFOSelect.m b/src/Select/LFOSelect.m index fbe132e..05bdfb7 100644 --- a/src/Select/LFOSelect.m +++ b/src/Select/LFOSelect.m @@ -9,10 +9,16 @@ function output = LFOSelect(amplitude, frequency, phase, fs, duration, input,number) %UNTITLED Summary of this function goes here % Detailed explanation goes here - if(number == "Option 1") + if(number == "AmplitudeSawtooth") output = lfo_sawtooth(amplitude, frequency, phase, fs, duration, input); - elseif(number == "Option 2") + elseif(number == "AmplitudeSine") output = lfo_sine(amplitude, frequency, phase, fs, duration, input); + elseif(number == "FrequencySine") + output = lfo_freq_sine(amplitude, frequency, phase, fs, duration, input); + elseif(number == "FrequencySquare") + output = lfo_freq_square(amplitude, frequency, phase, fs, duration, input); + elseif(number == "FrequencySawtooth") + output = lfo_freq_saw(amplitude, frequency, phase, fs, duration, input); else output = input; end diff --git a/src/Select/OffsetSelect.m b/src/Select/OffsetSelect.m index a8b982c..7bd053c 100644 --- a/src/Select/OffsetSelect.m +++ b/src/Select/OffsetSelect.m @@ -7,9 +7,9 @@ %Pass-through function used by app function output = OffsetSelect(input,value,number) - if(number == "Option 1") + if(number == "Echo") output = Meghaj_Echo(input, value); - elseif(number == "Option 2") + elseif(number == "PitchOffset") output = Petha_Hsu_PitchOffset(input, value); else output = input; diff --git a/src/Select/PitchEnvelopeSelect.m b/src/Select/PitchEnvelopeSelect.m index 997d30f..9d65ae9 100644 --- a/src/Select/PitchEnvelopeSelect.m +++ b/src/Select/PitchEnvelopeSelect.m @@ -7,9 +7,9 @@ %Pass-through function used by app function output = PitchEnvelopeSelect(input, Fs, attack,decay,sustain,release,number) - if(number == "Option 1") + if(number == "Logarithmic") output = DarellAnnePitchEnvelope(input, Fs, attack,decay,sustain,release); - elseif(number == "Option 2") + elseif(number == "Linear") output = DarellAnneLinearPitchEnvelope(input, Fs, attack,decay,sustain,release); else output = input; diff --git a/src/Select/SoundGeneratorSelect.m b/src/Select/SoundGeneratorSelect.m index 3fe715a..35ebd64 100644 --- a/src/Select/SoundGeneratorSelect.m +++ b/src/Select/SoundGeneratorSelect.m @@ -1,26 +1,62 @@ -%Written by Darell +%Written by Darell, edited by Arthur Lu % CONTRIBUTORS: % Person1: Darell +% Person2: Arthur Lu % DOCUMENTATION: %Pass-through function used by app function output = SoundGeneratorSelect(amplitude, frequency, phase, fs, duration, duty,number) - if(number == "Option 1") + if(number == "Sine") output = generate_sine(amplitude, frequency, phase, fs, duration, duty); - elseif(number == "Option 2") + elseif(number == "Square") output = generate_square(amplitude, frequency, phase, fs, duration, duty); - elseif(number == "Option 3") + elseif(number == "Triangle") output = generate_triangle(amplitude, frequency, phase, fs, duration, duty); - elseif(number == "Option 4") + elseif(number == "Sawtooth") output = generate_sawtooth(amplitude, frequency, phase, fs, duration, duty); - elseif(number == "Option 5") + elseif(number == "WhiteNoise") output = generate_white(amplitude, fs, duration); - elseif(number == "Option 6") + elseif(number == "HalfCircle") output = generate_halfCircles(amplitude, frequency, phase, fs, duration, duty); - else - output = 0; - end -end + elseif(number == "Trapezoid") + output = generate_trapezoid(amplitude, frequency, phase, fs, duration, duty); + elseif(number == "Pulse") + output = generate_pulse(amplitude, frequency, phase, fs, duration, duty); + elseif(number == "Cosine") + output = generate_cosine(amplitude, frequency, phase, fs, duration, duty); + elseif(number == "Heartbeat") + output = generate_heartbeat(amplitude, frequency, phase, fs, duration, duty); + % instruments: + elseif(number == "ArcoStrings") + output = generate_arcoStrings(amplitude, frequency, phase, fs, duration, duty); + elseif(number == "Bassoon") + output = generate_bassoon(amplitude, frequency, phase, fs, duration, duty); + elseif(number == "Clarinet") + output = generate_clarinet(amplitude, frequency, phase, fs, duration, duty); + elseif(number == "Flute") + output = generate_flute(amplitude, frequency, phase, fs, duration, duty); + elseif(number == "Horn") + output = generate_horn(amplitude, frequency, phase, fs, duration, duty); + elseif(number == "Oboe") + output = generate_oboe(amplitude, frequency, phase, fs, duration, duty); + elseif(number == "Organ") + output = generate_organ(amplitude, frequency, phase, fs, duration, duty); + elseif(number == "Saxophone") + output = generate_saxophone(amplitude, frequency, phase, fs, duration, duty); + elseif(number == "ShepardsCarillon") + output = generate_shepardsCarillon(amplitude, frequency, phase, fs, duration, duty); + elseif(number == "ShepardsOrgan") + output = generate_shepardsOrgan(amplitude, frequency, phase, fs, duration, duty); + elseif(number == "ShepardsStrings") + output = generate_shepardsStrings(amplitude, frequency, phase, fs, duration, duty); + elseif(number == "Trumpet") + output = generate_trumpet(amplitude, frequency, phase, fs, duration, duty); + elseif(number == "TubularBells") + output = generate_tubularBells(amplitude, frequency, phase, fs, duration, duty); + else + output = zeros(1, fs * duration); + end +end \ No newline at end of file