diff --git a/README.md b/README.md index e2a7772..1807172 100644 --- a/README.md +++ b/README.md @@ -2,18 +2,56 @@ Audio synthesizer project created by ECE 45 students, written using the MATLAB language and MATLAB GUI + ## Contributors Will add member names shortly ## Function Prototypes - -function x = generate_wave(amplitude, frequency, phase, fs, duration, duty) - -fuction x = envelope(input, fs, period, attack , decay, sustain, release) +Templates to create your own functions. + + ### Wave generating function +``` +function x = generate_WAVENAME(amplitude, frequency, phase, fs, duration, duty) +% GENERATE_WAVENAME: returns a matrix of sampled WAVENAME wave + +% CONTRIBUTORS: +% Person1: how you contributed +% Person2: how you contributed +% etc + +% 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 + YOUR CODE HERE + end +end +``` +NOTE: duty does not apply to some functions (such as sinusoids) + + ### Envelope function +``` +function x = envelope(input, fs, period, attack , decay, sustain, release) +``` where attack, decay, release are percentages between 0 to 1 of the period sustain is the percentage of the amplitude it should sustain for **envelope can be pitch or amplitude envelope** + +### Filter function +``` function output_timedomain = Filter(input_soundin_timedomain, Fs, LOW, MED, HIGH) +``` where LOW, MED, HIGH are user-selected variables of any value. **output should be in time domain for all functions (new sound)** diff --git a/src/.DS_Store b/src/.DS_Store index 5008ddf..14624d2 100644 Binary files a/src/.DS_Store and b/src/.DS_Store differ diff --git a/src/Main_test.m b/src/Main_test.m index 9eb7060..1ebd646 100644 --- a/src/Main_test.m +++ b/src/Main_test.m @@ -39,5 +39,4 @@ release = 0.1; x = DarellAmplitudeEnvelope(x, fs, attack,decay,sustain,release); %output new sound in time domain %play over 5 counts, should only hear 200hz playtime = 5; -play_continuous(x, fs, playtime) - +play_continuous(x, fs, playtime) \ No newline at end of file diff --git a/src/add_sine.m b/src/add_sine.m new file mode 100644 index 0000000..e0354fe --- /dev/null +++ b/src/add_sine.m @@ -0,0 +1,34 @@ +function x = add_sine(amplitude, fundamental, harmonics, fs, duration) +% ADD_SINE: Additive sine wave synthesis + +%CONTRIBUTORS: +%Benjamin Liou: Original author + +% DOCUMENTATION: +% harmonics should ideally be a 1D matrix of: + % overtones: positive integers + % undertones: 1/ positive integers + % example: [1/2, 1, 2, 3] + % NOTE: pitch of the fundamental frequency will still be perceived even + % when the fundamental itself is missing. ex. [4,5,6] + +% NOTE: it seems like when MATLAB's built in sound() takes in values, + % magnitudes over 1 get distorted. + + + + % initialize local variables from input arguments + n = fs * duration; % number of samples (length of matrix) + + % initialize a one dimensional zero matrix to be populated + x = zeros(1, n); + + % populate matrix by adding sine waves + for harmonic = harmonics + x = x + generate_sine(1, fundamental * harmonic, 0, fs, duration); + end + + % scale to amplitude + scalar = max(abs(x)); + x = x / scalar * amplitude; +end \ No newline at end of file diff --git a/src/amplify.m b/src/amplify.m new file mode 100644 index 0000000..153767b --- /dev/null +++ b/src/amplify.m @@ -0,0 +1,8 @@ +function output = amplify(input, multiplier) + %input: a 1D array representing the sound signal in the time domain + %multiplier: a scalar that multiplier all values in the input array to + % amplify or decrease the volume. + %Returns: input signal scaled by the multiplier in the time domain. + %Author: Conner Hsu + output = input*multiplier; +end \ No newline at end of file diff --git a/src/amplifyFreqRange.m b/src/amplifyFreqRange.m new file mode 100644 index 0000000..88adc8d --- /dev/null +++ b/src/amplifyFreqRange.m @@ -0,0 +1,23 @@ +function output = amplifyFreqRange(input, fs, low, high, multiplier) + %Amplifies frequencies within a specified range, leaves all other + %frequencies the same. + %By Conner Hsu + + %input: 1D array representing the sound signal in the time domain + %fs: sampling frequency + %low: a scalar representing the lower bound of frequencies to be amplified + %high: a scalar representing the upper bound of frequencies to be amplified + %multiplier: a scalar that multiplies frequencies between low and high + %Returns modified signal in the time domain. + + len = length(input); + f = fs*(-len/2:len/2-1)/len; + + outputW = fftshift(fft(input)); + for i = 1:length(outputW) + if (low < abs(f(i)) && abs(f(i)) < high) + outputW(i) = outputW(i)*multiplier; + end + end + output = real(ifft(fftshift(outputW))); +end \ No newline at end of file diff --git a/src/generate_sawtooth.m b/src/generate_sawtooth.m new file mode 100644 index 0000000..76e1726 --- /dev/null +++ b/src/generate_sawtooth.m @@ -0,0 +1,40 @@ +function x = generate_sawtooth(amplitude, frequency, phase, fs, duration, duty) +% generate_sawtooth: returns a matrix of sampled sawtooth wave + +% CONTRIBUTORS: +% Ben Zhang: Function 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 is a number between 0 and 1 + %duty does not apply for sawtooth wave + + % 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 + period = 1 / frequency; % period of the wave + + % initialize a one dimensional zero matrix to be populated + x = zeros(1, n); + + + % populate the matrix + for i = 1:n + t = i * dt; % time of the i'th sample + st = mod(frequency * t - phase, 1); % Progression through cycle + + slope = 2 * amplitude / period; % the incline slope from start to amplitude + mid = period / 2; + + %part before the straght vertical line + if(st < mid) + x(i) = slope * st; % amplitude from start to +amplitude + + %part after the straght vertical line + else + x(i) = slope * (st - 0.5) - amplitude; %amplitude from -amplitude to start + + end +end diff --git a/src/generate_sine.m b/src/generate_sine.m index 4add313..86a86fc 100644 --- a/src/generate_sine.m +++ b/src/generate_sine.m @@ -1,15 +1,28 @@ function x = generate_sine(amplitude, frequency, phase, fs, duration, duty) -%GENERATE_SINE:Arthur Lu returns a matrix of sampled sine wave, where the -%phase shift is in number of periods - x = zeros(1, fs * duration); - A = amplitude; - f = frequency; - p = phase; - n = fs * duration; - dt = 1 / fs; +% GENERATE_SINE: returns a matrix of sampled sine wave + +% CONTRIBUTORS: +% Arthur Lu: Original author +% Benjamin Liou: refactoring and annotations + +% 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 sinusoids + + + % 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) = A * sin(2 * pi * f * t - p); + t = i * dt; % time at the i'th sample + x(i) = amplitude * sin(2 * pi * frequency * t - phase); end end diff --git a/src/generate_square.m b/src/generate_square.m index bf3134e..1abc6f3 100644 --- a/src/generate_square.m +++ b/src/generate_square.m @@ -1,19 +1,40 @@ function x = generate_square(amplitude, frequency, phase, fs, duration, duty) -%GENERATE_SINE:Arthur Lu returns a matrix of sampled sine wave, where the -%phase shift is in number of periods - x = zeros(1, fs * duration); - A = amplitude; - f = frequency; - p = phase; - n = fs * duration; - dt = 1 / fs; +% GENERATE_SQUARE: returns a matrix of sampled square wave + +% CONTRIBUTORS: +% Arthur Lu: Original author +% Benjamin Liou: refactoring and annotations + +% 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 or less would return -amplitude for all sample points + % duty of 0.25 would return +amplitude for first quarter of each cycle + % then return -amplitude for the remaining three-fourths + % duty of 1 would return all +amplitude + + +% 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; - st = mod(f * t - p, 1); + t = i * dt; % time at the i'th sample + + % periodic ramp from 0 to 1 + % progression through a cycle + st = mod(frequency * t - phase, 1); + if(st < duty) - x(i) = A; + x(i) = amplitude; else - x(i) = -A; + x(i) = -amplitude; end end end diff --git a/src/generate_triangle.m b/src/generate_triangle.m index 94b78ad..f1a50ca 100644 --- a/src/generate_triangle.m +++ b/src/generate_triangle.m @@ -1,19 +1,43 @@ function x = generate_triangle(amplitude, frequency, phase, fs, duration, duty) -%GENERATE_SINE:Arthur Lu returns a matrix of sampled sine wave, where the -%phase shift is in number of periods - x = zeros(1, fs * duration); - A = amplitude; - f = frequency; - p = phase; - n = fs * duration; - dt = 1 / fs; +% GENERATE_TRIANGLE: returns a matrix of sampled square wave + +% CONTRIBUTORS: +% Arthur Lu: Original author +% Benjamin Liou: refactoring and annotations + +% 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.25 would have positive slope for first quarter of each cycle + % then have negative slope for the remaining three-fourths + + + +% 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; - st = mod(f * t - p, 1); + + % periodic ramp from 0 to 1 + % progression through a cycle + st = mod(frequency * t - phase, 1); + if(st < duty) - x(i) = A*(1/duty * st - 0.5); + slope = amplitude / duty; + intercept = -0.5 * amplitude; + x(i) = slope * st + intercept; else - x(i) = A*(-(1/(1-duty))*st + (duty/(1-duty)) + 1 - 0.5); + slope = -amplitude / (1 - duty); + intercept = amplitude*( duty/(1-duty) + 0.5); + x(i) = slope * st + intercept; end end end \ No newline at end of file diff --git a/src/generate_white.m b/src/generate_white.m new file mode 100644 index 0000000..ce3fb2d --- /dev/null +++ b/src/generate_white.m @@ -0,0 +1,13 @@ +function x = generate_white(amplitude, fs, duration) +%GENERATE_WHITE: returns a matrix of sampled white noise + +%CONTRIBUTORS: +%Benjamin Liou: Original author + +%DOCUMENTATION: +% white noise can then be filtered to produce different hues of noises + + +%time domain matrix of random sample points between +-amplitude +x = amplitude * 2 * (rand(1, fs * duration) - 0.5); +end \ No newline at end of file diff --git a/src/lfo_sine.m b/src/lfo_sine.m new file mode 100644 index 0000000..a9acbdb --- /dev/null +++ b/src/lfo_sine.m @@ -0,0 +1,29 @@ +function x = lfo_sine(amplitude, frequency, phase, fs, duration, input) +% LFO_SINE: modulates an input matrix + +% CONTRIBUTORS: +% Benjamin Liou: Original author + +% DOCUMENTATION: +% frequency is typically below 20Hz (according to wikipedia) +% fs and duration should be 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 lfo, which will be used to modulate the input + lfo = zeros(1, n); + + % populate lfo matrix + for i = 1:n + t = i * dt; % time at the i'th sample + lfo(i) = amplitude * sin(2 * pi * frequency * t - phase); + end + + % modulate input + x = lfo .* input; + +end \ No newline at end of file diff --git a/src/reverse.m b/src/reverse.m new file mode 100644 index 0000000..586c606 --- /dev/null +++ b/src/reverse.m @@ -0,0 +1,6 @@ +function output = reverse(input) + %input: a 1D array representing the sound signal in the time domain + %returns: the input signal with its elements in reverse order. + %By Conner Hsu + output = flip(input); +end \ No newline at end of file