diff --git a/.DS_Store b/.DS_Store index ca1e61b..dd306f7 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/App/app.mlapp b/App/app.mlapp index 60f0bbc..85352a0 100644 Binary files a/App/app.mlapp and b/App/app.mlapp differ diff --git a/README.md b/README.md index 1807172..65d2e76 100644 --- a/README.md +++ b/README.md @@ -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 14624d2..a262e39 100644 Binary files a/src/.DS_Store and b/src/.DS_Store differ diff --git a/src/DarellAmplitudeEnvelope.m b/src/AmpEnvelope/DarellAmplitudeEnvelope.m similarity index 82% rename from src/DarellAmplitudeEnvelope.m rename to src/AmpEnvelope/DarellAmplitudeEnvelope.m index 985c347..f3036ff 100644 --- a/src/DarellAmplitudeEnvelope.m +++ b/src/AmpEnvelope/DarellAmplitudeEnvelope.m @@ -1,3 +1,14 @@ +%Written by Darell +%Creates a Linear Amplitude Envelope + +% CONTRIBUTORS: +% Person1: Darell + +% DOCUMENTATION: +% fs is the sampling frequency +% attack, decay, release are in percentages of the period +% sustain is in the percentage of amplitude + function output = DarellAmplitudeEnvelope(input, Fs, attack,decay,sustain,release) %percentages for attack, decay, sustain, release len = length(input); T = (len-1)/Fs; diff --git a/src/DarellbandpassFilter.m b/src/Filter/DarellbandpassFilter.m similarity index 66% rename from src/DarellbandpassFilter.m rename to src/Filter/DarellbandpassFilter.m index fd23c4b..c271137 100644 --- a/src/DarellbandpassFilter.m +++ b/src/Filter/DarellbandpassFilter.m @@ -1,3 +1,15 @@ +%Written by Darell +%uses fourier transform to get the series of all signals + +% CONTRIBUTORS: +% Person1: Darell + +% DOCUMENTATION: +% fs is the sampling frequency +% y is the signal input +% LOW and HIGH are used for the band of frequency +% MEDIUM IS NOT USED + function output_y = DarellbandpassFilter(y,Fs,LOW,MED,HIGH) Len = length(y); F = Fs * (-Len/2 : (Len/2 - 1))/Len ; diff --git a/src/amplifyFreqRange.m b/src/Filter/amplifyFreqRange.m similarity index 100% rename from src/amplifyFreqRange.m rename to src/Filter/amplifyFreqRange.m diff --git a/src/bandreject_filter.m b/src/Filter/bandreject_filter.m similarity index 100% rename from src/bandreject_filter.m rename to src/Filter/bandreject_filter.m diff --git a/src/epic_effect_schluep.m b/src/Filter/epic_effect_schluep.m similarity index 100% rename from src/epic_effect_schluep.m rename to src/Filter/epic_effect_schluep.m diff --git a/src/muffled_effect_schluep.m b/src/Filter/muffled_effect_schluep.m similarity index 100% rename from src/muffled_effect_schluep.m rename to src/Filter/muffled_effect_schluep.m diff --git a/src/seperate_prevalent_schluep.m b/src/Filter/seperate_prevalent_schluep.m similarity index 100% rename from src/seperate_prevalent_schluep.m rename to src/Filter/seperate_prevalent_schluep.m diff --git a/src/FilterSelect.m b/src/FilterSelect.m deleted file mode 100644 index 1fb7596..0000000 --- a/src/FilterSelect.m +++ /dev/null @@ -1,10 +0,0 @@ -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/generate_halfCircles.m b/src/Generators/generate_halfCircles.m similarity index 100% rename from src/generate_halfCircles.m rename to src/Generators/generate_halfCircles.m diff --git a/src/generate_sawtooth.m b/src/Generators/generate_sawtooth.m similarity index 100% rename from src/generate_sawtooth.m rename to src/Generators/generate_sawtooth.m diff --git a/src/generate_sine.m b/src/Generators/generate_sine.m similarity index 100% rename from src/generate_sine.m rename to src/Generators/generate_sine.m diff --git a/src/generate_square.m b/src/Generators/generate_square.m similarity index 100% rename from src/generate_square.m rename to src/Generators/generate_square.m diff --git a/src/generate_triangle.m b/src/Generators/generate_triangle.m similarity index 100% rename from src/generate_triangle.m rename to src/Generators/generate_triangle.m diff --git a/src/generate_white.m b/src/Generators/generate_white.m similarity index 100% rename from src/generate_white.m rename to src/Generators/generate_white.m diff --git a/src/Helper/.DS_Store b/src/Helper/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/src/Helper/.DS_Store differ diff --git a/src/Helper/Equalizer_Darell.m b/src/Helper/Equalizer_Darell.m new file mode 100644 index 0000000..7d36f76 --- /dev/null +++ b/src/Helper/Equalizer_Darell.m @@ -0,0 +1,20 @@ +%Written by Darell + +% CONTRIBUTORS: +% Person1: Darell + +% DOCUMENTATION: +% fs is the sampling frequency +% input is the signal input +% EQplot is the curve generated by the EQ in the app. it should look like /----\ when everthing is set to 1 + + +function output = Equalizer_Darell(input,EQplot,Fs) +%It's an EQ written by Darell +% Split into frequencies and multiply by EQ + Mod_Freq = fftshift(fft(input)); + filtered_Mod_Freq = fftshift(Mod_Freq .* EQplot); + output = real(ifft(filtered_Mod_Freq)); + %plot(output); +end + diff --git a/src/Helper/MIDIDarell.m b/src/Helper/MIDIDarell.m new file mode 100644 index 0000000..19491c4 --- /dev/null +++ b/src/Helper/MIDIDarell.m @@ -0,0 +1,92 @@ +function output = MIDIDarell(dur,Fs) +%Darell Chua Yun Da +% Detailed explanation goes here + + freq = [330 350 370 392 415 440 466 494 523 554]; + charls = ["q" "w" "e" "r" "t" "y" "u" "i" "o" "p"]; + bytedur = 0.5; + x = 0:1/Fs:bytedur; + yz0 = zeros([1,(length(x)-1)]); + y = [yz0 + yz0 + yz0 + yz0 + yz0 + yz0 + yz0 + yz0 + yz0 + yz0]; + + for c = 1:length(freq) + for i=1:length(x) + y(c,i) = 0.5*sin(2*pi*freq(c)*x(i)); + end + end + Len = dur*Fs; + output = zeros([1,Len]); + + + + set(gcf,'CurrentCharacter', '@'); + figure(1) + + tStart = tic; + tEnd = toc(tStart); + figure(1) + + while(tEnd <= dur) + title("Midi Popup") + drawnow + char = get(gcf,'CurrentCharacter'); + while (char == '@' && tEnd <= dur) + figure(1) + char = get(gcf,'CurrentCharacter'); + tEnd = toc(tStart); + drawnow + end + + n = round((tEnd/dur)*Len); + + endt = tEnd + bytedur; + overt = tEnd + bytedur/3; + if overt> dur + endt = dur; + end + if endt > dur + endt = dur; + end + endn = round(endt*Fs); + + charno = 0; + for i=1:length(freq) + if char == charls(i) + charno = i; + end + end + if charno > 0 + sound(y(charno,:),Fs); + oldout = output(n:endn); + output(n:endn) = oldout + y(charno,1:(endn-n+1)); + while(tEnd < overt) + tEnd = toc(tStart); + drawnow + end + figure(1) + plot(output); + title("Midi Popup") + drawnow + set(gcf,'CurrentCharacter', '@') + else + figure(1) + drawnow + set(gcf,'CurrentCharacter', '@') + end + tEnd = toc(tStart); + end + figure(1) + plot(output); + sound(output,Fs); + drawnow(); +end + diff --git a/src/amplify.m b/src/Helper/amplify.m similarity index 100% rename from src/amplify.m rename to src/Helper/amplify.m diff --git a/src/play_continuous.m b/src/Helper/play_continuous.m similarity index 100% rename from src/play_continuous.m rename to src/Helper/play_continuous.m diff --git a/src/play_wave.m b/src/Helper/play_wave.m similarity index 100% rename from src/play_wave.m rename to src/Helper/play_wave.m diff --git a/src/plot_wave.m b/src/Helper/plot_wave.m similarity index 100% rename from src/plot_wave.m rename to src/Helper/plot_wave.m diff --git a/src/reverse.m b/src/Helper/reverse.m similarity index 100% rename from src/reverse.m rename to src/Helper/reverse.m diff --git a/src/lfo_sawtooth.m b/src/LFO/lfo_sawtooth.m similarity index 100% rename from src/lfo_sawtooth.m rename to src/LFO/lfo_sawtooth.m diff --git a/src/lfo_sine.m b/src/LFO/lfo_sine.m similarity index 100% rename from src/lfo_sine.m rename to src/LFO/lfo_sine.m diff --git a/src/NotWorking/.DS_Store b/src/NotWorking/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/src/NotWorking/.DS_Store differ diff --git a/src/Daniel_Doan_convolution.m b/src/NotWorking/Daniel_Doan_convolution.m similarity index 100% rename from src/Daniel_Doan_convolution.m rename to src/NotWorking/Daniel_Doan_convolution.m diff --git a/src/add_sine.m b/src/NotWorking/add_sine.m similarity index 100% rename from src/add_sine.m rename to src/NotWorking/add_sine.m diff --git a/src/fade_in.m b/src/NotWorking/fade_in.m similarity index 100% rename from src/fade_in.m rename to src/NotWorking/fade_in.m diff --git a/src/fade_out.m b/src/NotWorking/fade_out.m similarity index 100% rename from src/fade_out.m rename to src/NotWorking/fade_out.m diff --git a/src/Meghaj_Echo.m b/src/Offset/Meghaj_Echo.m similarity index 100% rename from src/Meghaj_Echo.m rename to src/Offset/Meghaj_Echo.m diff --git a/src/Petha_Hsu_PitchOffset.m b/src/Offset/Petha_Hsu_PitchOffset.m similarity index 100% rename from src/Petha_Hsu_PitchOffset.m rename to src/Offset/Petha_Hsu_PitchOffset.m diff --git a/src/PitchEnvelope/DarellAnneLinearPitchEnvelope.m b/src/PitchEnvelope/DarellAnneLinearPitchEnvelope.m new file mode 100644 index 0000000..7893537 --- /dev/null +++ b/src/PitchEnvelope/DarellAnneLinearPitchEnvelope.m @@ -0,0 +1,103 @@ +%Written by Darell and Anne +%If there is a frequency of 200Hz: +%1. it needs to ramp up a frequency from 0Hz to the 200Hz over the attack time +%2. It needs to ramp down to a set sustained frequency over the decay time e.g. 160Hz < 200Hz +%3. It maintains this 160Hz until the release time +%4. Release time: It decays from 160Hz further all the way back to 0Hz. +%This envelope uses linear calculations + +% CONTRIBUTORS: +% Person1: Darell +% Person2: Anne + +% DOCUMENTATION: +% fs is the sampling frequency +% attack, decay, release are in percentages of the period +% sustain is in the percentage of amplitude + +function output = DarellAnneLinearPitchEnvelope(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; + x = 1:len; + y = x .* 0; + g = x .* 0; + while tcounter <= curr + ncount = round((tcounter^2)/(2*curr)+ curr/2); + y(tcounter) = ncount; %For Debug Purposes + output(tcounter) = input(ncount); + tcounter = tcounter+1; + end + + %decay phase + prevcur = curr; + tcounter = prevcur; + curr = decaytime; + while tcounter <= curr + + t = round(tcounter-prevcur); + dur = round(curr-prevcur); + dsus = (1-sustain); + + dn = (1 - (dsus)*t/(2*dur))*t; + ncount = round(prevcur + dn); + tcounter = round(tcounter); + + y(tcounter) = ncount; %For Debug Purposes + output(tcounter) = input(ncount); + tcounter = tcounter+1; + end + hold on + plot(x,y) + plot(x,g) + hold off + %sustain phase + prevncount = ncount; + prevcur = curr; + tcounter = prevcur; + curr = sustaintime; + while tcounter <= curr + t = round(tcounter-prevcur); + ncount = round(sustain*(t) + prevncount); + tcounter = round(tcounter); + + y(tcounter) = ncount; %For Debug Purposes + output(tcounter) = input(ncount); + tcounter = tcounter+1; + end + + %release phase + prevncount = ncount; + prevcur = curr; + tcounter = prevcur; + curr = Fs; + while tcounter <= curr + t = round(tcounter-prevcur); + dur = round(curr-prevcur); + + dn = (sustain - (sustain)*t/(2*dur))*t; + ncount = round(prevncount + dn); + + %ncount = round(prevncount + ((curr-prevcur)*(tcounter-prevcur)/(curr))*(1-log(tcounter+1-prevcur)/log(curr-prevcur))); + + %ncount = round(curr*(1-log(tcounter)/log(prevcur)) + prevncount); + + tcounter = round(tcounter); + y(tcounter) = ncount; %For Debug Purposes + if ncount > len + output(tcounter) = 0; + else + output(tcounter) = input(ncount); + end + tcounter = tcounter+1; + end + plot(x,y) %For Debug Purposes +end \ No newline at end of file diff --git a/src/DarellAnnePitchEnvelope.m b/src/PitchEnvelope/DarellAnnePitchEnvelope.m similarity index 97% rename from src/DarellAnnePitchEnvelope.m rename to src/PitchEnvelope/DarellAnnePitchEnvelope.m index 6b5643f..279e31b 100644 --- a/src/DarellAnnePitchEnvelope.m +++ b/src/PitchEnvelope/DarellAnnePitchEnvelope.m @@ -4,6 +4,7 @@ %2. It needs to ramp down to a set sustained frequency over the decay time e.g. 160Hz < 200Hz %3. It maintains this 160Hz until the release time %4. Release time: It decays from 160Hz further all the way back to 0Hz. +%This envelope uses logarithmic calculations % CONTRIBUTORS: % Person1: Darell diff --git a/src/AmpEnvelopeSelect.m b/src/Select/AmpEnvelopeSelect.m similarity index 69% rename from src/AmpEnvelopeSelect.m rename to src/Select/AmpEnvelopeSelect.m index 1492f51..885204a 100644 --- a/src/AmpEnvelopeSelect.m +++ b/src/Select/AmpEnvelopeSelect.m @@ -1,3 +1,11 @@ +%Written by Darell + +% CONTRIBUTORS: +% Person1: Darell + +% DOCUMENTATION: +%Pass-through function used by app + function output = AmpEnvelopeSelect(input, Fs, attack,decay,sustain,release,number) if(number == "Option 1") output = DarellAmplitudeEnvelope(input, Fs, attack,decay,sustain,release); diff --git a/src/Select/FilterSelect.m b/src/Select/FilterSelect.m new file mode 100644 index 0000000..659a0d1 --- /dev/null +++ b/src/Select/FilterSelect.m @@ -0,0 +1,26 @@ +%Written by Darell + +% CONTRIBUTORS: +% Person1: Darell + +% DOCUMENTATION: +%Pass-through function used by app + +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); + elseif(number == "Option 3") + output = epic_effect_schluep(input, Fs, LOW, MED, HIGH); + elseif(number == "Option 4") + output = muffled_effect_schluep(input, Fs, LOW, MED, HIGH); + elseif(number == "Option 5") + output = seperate_prevalent_schluep(input, Fs, LOW, MED, HIGH); + elseif(number == "Option 6") + output = bandreject_filter(input, Fs, LOW, HIGH); + else + output = input; + end +end + diff --git a/src/Select/LFOSelect.m b/src/Select/LFOSelect.m new file mode 100644 index 0000000..fbe132e --- /dev/null +++ b/src/Select/LFOSelect.m @@ -0,0 +1,20 @@ +%Written by Darell + +% CONTRIBUTORS: +% Person1: Darell + +% DOCUMENTATION: +%Pass-through function used by app + +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") + output = lfo_sawtooth(amplitude, frequency, phase, fs, duration, input); + elseif(number == "Option 2") + output = lfo_sine(amplitude, frequency, phase, fs, duration, input); + else + output = input; + end +end + diff --git a/src/Select/OffsetSelect.m b/src/Select/OffsetSelect.m new file mode 100644 index 0000000..a8b982c --- /dev/null +++ b/src/Select/OffsetSelect.m @@ -0,0 +1,19 @@ +%Written by Darell + +% CONTRIBUTORS: +% Person1: Darell + +% DOCUMENTATION: +%Pass-through function used by app + +function output = OffsetSelect(input,value,number) + if(number == "Option 1") + output = Meghaj_Echo(input, value); + elseif(number == "Option 2") + output = Petha_Hsu_PitchOffset(input, value); + else + output = input; + end +end + + diff --git a/src/PitchEnvelopeSelect.m b/src/Select/PitchEnvelopeSelect.m similarity index 51% rename from src/PitchEnvelopeSelect.m rename to src/Select/PitchEnvelopeSelect.m index 91bc91c..997d30f 100644 --- a/src/PitchEnvelopeSelect.m +++ b/src/Select/PitchEnvelopeSelect.m @@ -1,6 +1,16 @@ +%Written by Darell + +% CONTRIBUTORS: +% Person1: Darell + +% DOCUMENTATION: +%Pass-through function used by app + function output = PitchEnvelopeSelect(input, Fs, attack,decay,sustain,release,number) if(number == "Option 1") output = DarellAnnePitchEnvelope(input, Fs, attack,decay,sustain,release); + elseif(number == "Option 2") + output = DarellAnneLinearPitchEnvelope(input, Fs, attack,decay,sustain,release); else output = input; end diff --git a/src/SoundGeneratorSelect.m b/src/Select/SoundGeneratorSelect.m similarity index 68% rename from src/SoundGeneratorSelect.m rename to src/Select/SoundGeneratorSelect.m index b964821..3fe715a 100644 --- a/src/SoundGeneratorSelect.m +++ b/src/Select/SoundGeneratorSelect.m @@ -1,3 +1,11 @@ +%Written by Darell + +% CONTRIBUTORS: +% Person1: Darell + +% DOCUMENTATION: +%Pass-through function used by app + function output = SoundGeneratorSelect(amplitude, frequency, phase, fs, duration, duty,number) if(number == "Option 1") output = generate_sine(amplitude, frequency, phase, fs, duration, duty); @@ -8,7 +16,9 @@ function output = SoundGeneratorSelect(amplitude, frequency, phase, fs, duration 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); + output = generate_white(amplitude, fs, duration); + elseif(number == "Option 6") + output = generate_halfCircles(amplitude, frequency, phase, fs, duration, duty); else output = 0; end diff --git a/src/generate_heartbeat.m b/src/generate_heartbeat.m new file mode 100644 index 0000000..40230d6 --- /dev/null +++ b/src/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