diff --git a/DarellsAnnex/app.mlapp b/DarellsAnnex/app.mlapp index 3fb8dca..de64f4f 100644 Binary files a/DarellsAnnex/app.mlapp and b/DarellsAnnex/app.mlapp differ diff --git a/src/DarellAnnePitchEnvelope.m b/src/DarellAnnePitchEnvelope.m new file mode 100644 index 0000000..dc147f6 --- /dev/null +++ b/src/DarellAnnePitchEnvelope.m @@ -0,0 +1,57 @@ +%Written by Darell and Anne + +function output = DarellAnnePitchEnvelope(input, Fs, attack,decay,sustain,release) %percentages for attack, decay, sustain, release + len = length(input); + T = (len-1)/Fs; + attacktime = attack * T * Fs; + decaytime = attacktime + decay * T * Fs; + sustaintime = (T - (release * T)) * Fs; + + output = zeros([1,len]); + + tcounter = 1; + %attack phase + curr = attacktime; + while tcounter <= curr + ncount = round(curr*log(tcounter)/log(curr)+1); + output(tcounter) = input(ncount); + tcounter = tcounter+1; + end + + %decay phase + prevcur = curr; + tcounter = prevcur; + curr = decaytime; + while tcounter <= curr + ncount = round(sustain*curr*(1-log(tcounter)/log(prevcur)) + prevcur); + tcounter = round(tcounter); + output(tcounter) + output(tcounter) = input(ncount); + tcounter = tcounter+1; + end + + %sustain phase + prevncount = ncount; + prevcur = curr; + tcounter = prevcur; + curr = sustaintime; + while tcounter <= curr + ncount = round(sustain*(tcounter - prevcur) + prevncount); + tcounter = round(tcounter); + output(tcounter) = input(ncount); + tcounter = tcounter+1; + end + + %release phase + prevncount = ncount; + prevcur = curr; + tcounter = prevcur; + curr = Fs; + while tcounter <= Fs + ncount = round(curr*(1-log(tcounter)/log(prevcur)) + prevncount); + tcounter = round(tcounter); + output(tcounter) = input(ncount); + tcounter = tcounter+1; + end + +end \ No newline at end of file diff --git a/src/FilterSelect.m b/src/FilterSelect.m new file mode 100644 index 0000000..1fb7596 --- /dev/null +++ b/src/FilterSelect.m @@ -0,0 +1,10 @@ +function output = FilterSelect(input,Fs,LOW,MED,HIGH,number) + if(number == "Option 1") + output = DarellbandpassFilter(input,Fs,LOW,MED,HIGH); + elseif(number == "Option 2") + output = amplifyFreqRange(input, Fs, LOW, MED, HIGH); + else + output = input; + end +end + diff --git a/src/Main_test.m b/src/Main_test.m index 31f53eb..1ebd646 100644 --- a/src/Main_test.m +++ b/src/Main_test.m @@ -13,7 +13,7 @@ x = x + generate_sine(amplitude, (frequency+5), phase, fs, duration, duty); %play over 5 counts, should hear both frequencies, 5 beats per second between the 2 frequencies playtime = 5; -play_continuous(x, fs, playtime) +%play_continuous(x, fs, playtime) LOW = 0; HIGH = frequency + 1; @@ -22,7 +22,14 @@ x = DarellbandpassFilter(x,fs,LOW,MED,HIGH); %play over 5 counts, should only hear 200hz playtime = 5; -play_continuous(x, fs, playtime) +%play_continuous(x, fs, playtime) + +attack = 0.2; +decay = 0.1; +sustain = 0.8; +release = 0.4; + +x = DarellAnnePitchEnvelope(x, Fs, attack,decay,sustain,release); attack = 0.2; decay = 0.2; diff --git a/src/Petha_Hsu_PitchOffset.m b/src/Petha_Hsu_PitchOffset.m index 908accf..feaa922 100644 --- a/src/Petha_Hsu_PitchOffset.m +++ b/src/Petha_Hsu_PitchOffset.m @@ -1,50 +1,50 @@ -% Petha_Hsu_PitchOffset: input a wave and pitch offset (in percentage) -% This function takes a input sound signal and increases the pitch by the -% offset percentage. The output is not 100% accurate. It is only an -% estimation as the information we the function works with is very limited. -% If 100% output is expected, more information like the frequency and type -% of wave would be required. And the estimation only works for -% f_offset > 0.5. Below 0.5, the output is problematic. Again, the output -% is just a good estimation. - -% CONTRIBUTORS: -% Pethaperumal Natarajan: I figured a way to increase the pitch of input -% signal by using fourier transform and shifting the frequency using a for -% loop. Then I used inverse transform to get a sound signal back in the time -% domain. -% Wesley Hsu: I helped solve the problem of being unable to lower frequency -% for the loop using the floor function. This allowed rounding to maintain -% the lower signals that were needed when the code returned the signal back -% into the time domain. - -function y = Petha_Hsu_PitchOffset(x, f_offset) - len = length(x); - X = fft(x); - X = fftshift(X); %Fourier transform the input wave - Y = zeros(1, len); - - midpoint = len/2; - for i = 1:len - %Shifting the Fourier transform in frequency domain to adjust the - %frequency of signal. - %Floor function is used as signals must be integers and not - %doubles. - if floor((i - midpoint) / f_offset + midpoint) < 1 || floor((i - midpoint) / f_offset + midpoint) > len - continue; - end - Y(i) = X(floor((i - midpoint) / f_offset + midpoint)); - end - - %Plotted graphs to troubleshoot the problem. - %Fs = 44800; - %f = Fs *(-len/2 : len/2 -1) / len; - %tiledlayout(1,3); nexttile; - %plot(f, abs(X)); title("input"); nexttile; - %plot(f, abs(Y)); title("output"); nexttile; - - - Y = fftshift(Y); - y = ifft(Y); - y = real(y); - +% Petha_Hsu_PitchOffset: input a wave and pitch offset (in percentage) +% This function takes a input sound signal and increases the pitch by the +% offset percentage. The output is not 100% accurate. It is only an +% estimation as the information we the function works with is very limited. +% If 100% output is expected, more information like the frequency and type +% of wave would be required. And the estimation only works for +% f_offset > 0.5. Below 0.5, the output is problematic. Again, the output +% is just a good estimation. + +% CONTRIBUTORS: +% Pethaperumal Natarajan: I figured a way to increase the pitch of input +% signal by using fourier transform and shifting the frequency using a for +% loop. Then I used inverse transform to get a sound signal back in the time +% domain. +% Wesley Hsu: I helped solve the problem of being unable to lower frequency +% for the loop using the floor function. This allowed rounding to maintain +% the lower signals that were needed when the code returned the signal back +% into the time domain. + +function y = Petha_Hsu_PitchOffset(x, f_offset) + len = length(x); + X = fft(x); + X = fftshift(X); %Fourier transform the input wave + Y = zeros(1, len); + + midpoint = len/2; + for i = 1:len + %Shifting the Fourier transform in frequency domain to adjust the + %frequency of signal. + %Floor function is used as signals must be integers and not + %doubles. + if floor((i - midpoint) / f_offset + midpoint) < 1 || floor((i - midpoint) / f_offset + midpoint) > len + continue; + end + Y(i) = X(floor((i - midpoint) / f_offset + midpoint)); + end + + %Plotted graphs to troubleshoot the problem. + %Fs = 44800; + %f = Fs *(-len/2 : len/2 -1) / len; + %tiledlayout(1,3); nexttile; + %plot(f, abs(X)); title("input"); nexttile; + %plot(f, abs(Y)); title("output"); nexttile; + + + Y = fftshift(Y); + y = ifft(Y); + y = real(y); + end \ No newline at end of file diff --git a/src/PitchEnvelopeSelect.m b/src/PitchEnvelopeSelect.m index 1cbe9d8..91bc91c 100644 --- a/src/PitchEnvelopeSelect.m +++ b/src/PitchEnvelopeSelect.m @@ -1,6 +1,6 @@ function output = PitchEnvelopeSelect(input, Fs, attack,decay,sustain,release,number) if(number == "Option 1") - output = DarellAmplitudeEnvelope(input, Fs, attack,decay,sustain,release); + output = DarellAnnePitchEnvelope(input, Fs, attack,decay,sustain,release); else output = input; end diff --git a/src/SoundGeneratorSelect.m b/src/SoundGeneratorSelect.m index 9c5c985..b964821 100644 --- a/src/SoundGeneratorSelect.m +++ b/src/SoundGeneratorSelect.m @@ -5,7 +5,10 @@ function output = SoundGeneratorSelect(amplitude, frequency, phase, fs, duration output = generate_square(amplitude, frequency, phase, fs, duration, duty); elseif(number == "Option 3") output = generate_triangle(amplitude, frequency, phase, fs, duration, duty); - + elseif(number == "Option 4") + output = generate_sawtooth(amplitude, frequency, phase, fs, duration, duty); + elseif(number == "Option 5") + output = generate_white(amplitude, frequency, phase, fs, duration, duty); else output = 0; end diff --git a/src/Strong_Bassline.mp3 b/src/Strong_Bassline.mp3 new file mode 100644 index 0000000..4d5f73e Binary files /dev/null and b/src/Strong_Bassline.mp3 differ diff --git a/src/bandreject_filter.m b/src/bandreject_filter.m new file mode 100644 index 0000000..8073a9e --- /dev/null +++ b/src/bandreject_filter.m @@ -0,0 +1,62 @@ +function output_y = 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 + % (basically exliminates them) + % By Yalu Ouyang + + + % Input: the input signal in the time domain + % Fs: the sampling frequency + % Low: the lower limit of the specified range + % High: the upper limit of the specified range + % Returns Output: the filtered signal in the time domain + + len = length(Input); + + F = Fs * (-len/2 : (len/2 - 1)) / len ; + + % modified signal in the frequency domain + % using Fourier Transform + mod_freq = fftshift(fft(Input)); + + len_f = length(mod_freq); + + % use this array to record the frequencies + % that should pass through + % 0 indicates reject + % 1 indicates pass + multiplier = zeros([1,len_f]); + + for index = 1 : len_f + + % within range of band reject + % so elminate these frequencies + if ((Low < abs(F(index))) && (abs(F(index)) < High)) + multiplier(index) = 0; + + % outside of specified range + % so shoudln't be altered + else + multiplier(index) = 1; + end + end + + % filtered signal in the frequency domain + filtered_mod_freq = fftshift(mod_freq .* multiplier); + + % convert signal back to the time domain + Output = real(ifft(filtered_mod_freq)); + +end + +% This function is useful for eliminating +% unwanted signals that have frequencies close to the +% median frequency of the original signal +% (consider overall frequencies as one part, +% this elminates the middle portion) + +% Fourier transform is applied in this function +% to make it easier to eliminate specified +% frequencies of the signal +% (easier to do so in the frequency domain) diff --git a/src/epic_effect_schluep.m b/src/epic_effect_schluep.m new file mode 100644 index 0000000..2ad7109 --- /dev/null +++ b/src/epic_effect_schluep.m @@ -0,0 +1,55 @@ +function output = epic_effect_schluep(input, Fs, LOW, MED, HIGH) +% epic_effect_schluep: Outputs a more "epic" version of the input sound. +% This is done by amplifying low frequencies and by implementing a chorus +% effect. A chorus effect is created when multiple copies of sound delayed +% by a small, random amount are added to the original signal. Works best on +% songs with a stronger bassline. +% Try this function out with "Strong_Bassline.mp3". + +% CONTRIBUTORS: +% Nicolas Schluep: Function Author + +% DOCUMENTATION: +% input: The input sound in the time-domain. +% Fs: The sampling rate of the input signal. A typical value is 44100 Hz. +% 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. + +Len = length(non_stereophonic); +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 +% input signal. fftshift() makes it such that the zero frequency is at the +% center of the array. +lowAmplifyFilter = zeros(1, length(inputFreq)); + +% Creating a filter which amplifies lower frequencies. +for i = 1:length(lowAmplifyFilter) + if abs(F(i)) < HIGH + lowAmplifyFilter(i) = 1.25; + else + lowAmplifyFilter(i) = 1.00; + end +end + +lowPassedInput = inputFreq .* transpose(lowAmplifyFilter); %Apply the "lowAmplifyFilter". + +% Adding the chorus effect. +realOutput = real(ifft(fftshift(lowPassedInput))); +output = realOutput; + +% Adding 100 randomly delayed signals to the original signal which creates the chorus effect. +for i = 1:100 + currentDelay = 0.003 * rand(); % The current delay of the sound in seconds. + currentIndex = round(currentDelay * Fs); % Find the first index where the sound should start playing. + delayedOutput = [zeros(currentIndex, 1); realOutput]; % Adds "currentIndex" zeros to the front of the + % "realOutput" vector to create a slightly delayed version of the signal. + delayedOutput = delayedOutput(1:length(realOutput)); % Truncates the "delayedOutput" + % vector so that it can be added to the "realOutput" vector. + output = output + delayedOutput; +end + +output = output ./ 100; % Divide by 100 to decrease the amplitude of the sound to a normal level. diff --git a/src/fade_in.m b/src/fade_in.m new file mode 100644 index 0000000..22bef76 --- /dev/null +++ b/src/fade_in.m @@ -0,0 +1,29 @@ +function output = fade_in(input, time) + % Creates a fade-in sound effect that lasts a given + % time parameter of the input sound signal + % By Yalu Ouyang + + + % input: a 1D array that represents the sound signal in the time domain + % time: how long the fade in effect should last + % Shouldn't be longer than the input signal (in which case the function + % treats it as the duration of the signal) + % Returns modified signal in the time domain (output). + + len = length(input); + + % if time parameter longer than signal, treat time as + % the duration of original signal + if time > len + time = len + end + + % set multiplier as 1D array + % fade in effect: from no volume to full volume of signal + multiplier = (1 : time) / time; + + % the resulting fade-in output + output = input .* multiplier; +end + +% This is useful for making videos, specifically the intro part diff --git a/src/fade_out.m b/src/fade_out.m new file mode 100644 index 0000000..f50812b --- /dev/null +++ b/src/fade_out.m @@ -0,0 +1,32 @@ +function output = fade_out(input, time) + % Creates a fade-out sound effect that lasts a given + % time parameter of the input sound signal + % By Yalu Ouyang + + % input: a 1D array that represents the sound signal in the time domain + % time: how long the fade out effect should last + % Shouldn't be longer than the input signal + % (in which case the function treats it as the duration of the signal) + % Returns modified signal in the time domain (output). + + len = length(input); + + % if time parameter longer than signal, treat time as + % the duration of original signal + if time > len + time = len + end + + % set multiplier as 1D array + + multiplier = (1 : time) / time; + + % fade out effect: from full volume of signal to no volume + multiplier = flip(multiplier) + + % the resulting fade-in output + output = input .* multiplier; +end + + +% This is useful for creating videos, specifically the outro part diff --git a/src/muffled_effect_schluep.m b/src/muffled_effect_schluep.m new file mode 100644 index 0000000..c193a38 --- /dev/null +++ b/src/muffled_effect_schluep.m @@ -0,0 +1,56 @@ +function output = muffled_effect_schluep(input, Fs, LOW, MED, HIGH) +% muffled_effect_schluep: Outputs a muffled version of the the original input +% sound in the time domain. This makes it sound as if the audio is being +% played in another room. +% Try this function out with "Strong_Bassline.mp3". + +% CONTRIBUTORS: +% Nicolas Schluep: Function Author + +% DOCUMENTATION: +% input: The input sound in the time-domain. +% Fs: The sampling rate of the input signal. A typical value is 44100 Hz. +% 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. + +Len = length(non_stereophonic); +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 +% input signal. fftshift() makes it such that the zero frequency is at the +% center of the array. +lowPassFilter = zeros(1, length(inputFreq)); + +% Creating Low Pass Filter +for i = 1:length(lowPassFilter) + if abs(F(i)) < HIGH + lowPassFilter(i) = 1; + else + lowPassFilter(i) = 0; + end +end + +lowPassedInput = inputFreq .* transpose(lowPassFilter); %Apply the low-pass filter. + +% Adding a slight reverb effect. +realOutput = real(ifft(fftshift(lowPassedInput))); + +delay = 0.001; % The delay of the sound in seconds. +index = round(delay*Fs); % Find the first index where sound should start playing +% by multiplying the delay by the sampling frequency. +delayedOutput = [zeros(index, 1); realOutput]; % Adds "index" zeros to the front of the +% "realOutput" vector to create a slightly delayed version of the signal. +delayedOutput = delayedOutput(1:length(realOutput)); % Truncates the "delayedOutput" +% vector so that it can be added to the "realOutput" vector. + +output = (realOutput + delayedOutput) ./ 2.0; % Adds the "realOutput" and "delayedOutput" +% vectors to create a reverb effect. Divides by 2 to avoid clipping +% effects. + + + + + diff --git a/src/seperate_prevalent_schluep.m b/src/seperate_prevalent_schluep.m new file mode 100644 index 0000000..3fbc7a6 --- /dev/null +++ b/src/seperate_prevalent_schluep.m @@ -0,0 +1,62 @@ +function output = seperate_prevalent_schluep(input, Fs, LOW, MED, HIGH) +% seperate_prevalent_schluep: Attempts to seperate the most prevalent frequencies +% from the input sound by finding the most prevalent frequencies and applying +% a band-pass filter to a small region around those frequencies. +% Try this function out with "Strong_Bassline.mp3". + +% CONTRIBUTORS: +% Nicolas Schluep: Function Author + +% DOCUMENTATION: +% input: The input sound in the time-domain. +% Fs: The sampling rate of the input signal. A typical value is 44100 Hz. +% HIGH: The maximum distance around the maximum frequency value that will +% 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. + +Len = length(non_stereophonic); +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 +% input signal. fftshift() makes it such that the zero frequency is at the +% center of the array. +bandPassFilter = zeros(1, length(inputFreq)); + +maxAmplitude = 0; +mostPrevalentFrequency = 0; + +% Finding the most prevalent frequency. +for i = round(length(inputFreq)/2):length(inputFreq) + if inputFreq(i) > maxAmplitude + maxAmplitude = inputFreq(i); + mostPrevalentFrequency = F(i); + end +end + +% Determining maximum and minimum frequency values for the Band Pass filter. +maxFrequency = mostPrevalentFrequency + HIGH; +minFrequency = mostPrevalentFrequency - HIGH; + +if minFrequency < 0.0 + minFrequency = 0.0; +end + +% Creating the Band-Pass filter. +for i = 1:length(bandPassFilter) + if (abs(F(i)) < maxFrequency) && (abs(F(i)) > minFrequency) + bandPassFilter(i) = 1; + else + bandPassFilter(i) = 0; + end +end + +bandPassedInput = inputFreq .* transpose(bandPassFilter); %Apply the Band-Pass Filter. + +output = real(ifft(fftshift(bandPassedInput))); + + + +