The objective of this project was to create a unique-sounding instrument using WL sound functions. I focused mainly on manipulating the amplitudes of harmonic overtones to create unique timbres, and multiplied different wave functions to further change the tone. The final product is a dynamic module in which one can change pitch, note length, and timbre through multiple types of variables.
Brief Introduction to Overtones
Brief Introduction to Overtones
An overtone is a frequency within a sound that is greater than the fundamental frequency, or main note of a given sound. Overtones and their amplitudes are the main factors in determining the timbre, or tone, of any given sound. Harmonic overtones are those whose frequencies are integer multiples of the fundamental frequency. In my project, I only focused on these overtones, specifically the first 10.
Creating Sounds with Harmonic Overtones
Creating Sounds with Harmonic Overtones
To create a sound with harmonic overtones, I created a function that would take frequency, note length, and a list of amplitudes, and play all the notes with their respective assigned amplitudes. Each overtone is the initial sine wave but with the frequency increased by n, and alternating negative and positive.
Here is a function that takes frequency, time, and a list of the amplitude of overtones, and outputs the sound those values create:
In[]:=
play[frequency_,time_,amp_List]:=Sound[Play[Total[Table[amp[[y]]((-1)^(y+1))*Sin[y*frequency*2*Pi*x],{y,1,Length[amp]}]],{x,0,time}]];
In order to add more options to change the timbre, I added three Boolean value elements that decide whether each overtone is multiplied by a sawtooth wave, triangle wave, and/or square wave, respectively.
In[]:=
play2[frequency_,time_,amp_List,saw_,tri_,sq_]:=Sound[Play[First[Total[Table[{amp[[y]]*((-1)^(y+1))*Sin[y*frequency*2*Pi*x] (*Initial Function*)*First[{If[saw,SawtoothWave[3y*x],1]}] (*if value is True, multiplies nth overtone by the wave of 3nx*)*First[{If[tri,TriangleWave[3y*x],1]}] *First[{If[sq,SquareWave[3y*x],1]}]},{y,1,Length[amp]}]]],{x,0,time}]];
Using Sound Functions in a Dynamic Module
Using Sound Functions in a Dynamic Module
My first step towards creating the full module was to create one with just changing pitch and overtone amplitudes. I used a sliders to control these values. Next to the pitch slider there are black and white dots to show what would be black and white keys on a keyboard, in order to make playing easier.
Here is my initial module with sliders for frequency, time, and each overtone
In[]:=
DynamicModule[{freq=440,time=.5,ov1=1,ov2=0,ov3=0,ov4=0,ov5=0,ov6=0,ov7=0,ov8=0,ov9=0,ov10=0},Dynamic[Row[{Invisible[Dynamic[EmitSound[play[freq,time,{ov1,ov2,ov3,ov4,ov5,ov6,ov7,ov8,ov9,ov10}]],SynchronousUpdatingFalse]], (*Emits a sound whenever the frequency is updated*)Row[{Column[Graphics[Style[Disk[{1,1},1],#]]&/@{White,Black,White,Black,White,White,Black,White,Black,White,Black,White,White,Black,White,Black,White} (*Column of dots*),ItemSize1,Spacings.1],VerticalSlider[Dynamic[freq],{{262,277,294,311,330,349,370,392,415,440,466,493,524,554,587,622,659}},ImageSize{30,275}] (*Vertical slider to change frequency*)}],Column[Row[{StringJoin["Overtone ",#[[1]]],Slider[#[[2]],{0,1,.1},ContinuousActionFalse]}] (*A slider for a generic overtone, applied to the below variables*)&/@{{"1 ",Dynamic[ov1]},{"2 ",Dynamic[ov2]},{"3 ",Dynamic[ov3]},{"4 ",Dynamic[ov4]},{"5 ",Dynamic[ov5]},{"6 ",Dynamic[ov6]},{"7 ",Dynamic[ov7]},{"8 ",Dynamic[ov8]},{"9 ",Dynamic[ov9]},{"10",Dynamic[ov10]}},ItemSize{20,2.6}]}],SaveDefinitionsTrue,TrackedSymbols{freq}]]
Out[]=
Overtone 1 |
Overtone 2 |
Overtone 3 |
Overtone 4 |
Overtone 5 |
Overtone 6 |
Overtone 7 |
Overtone 8 |
Overtone 9 |
Overtone 10 |
Adding More Variables to Create the Final Product
Adding More Variables to Create the Final Product
In order to create the full module, I added capabilities to change note length with a slider, as well as began using play2 instead of play. This meant that it also has the option to multiply by the three other waves with checkboxes, creating a wider range of sound options. I also added 5 basic overtone settings in, so that if the player wants to quickly get a simple sound they only have to push one button.
Here is the updated module, with the additional features being added within the outermost row:
In[]:=
DynamicModule[{freq=440,time=.5,ov1=1,ov2=0,ov3=0,ov4=0,ov5=0,ov6=0,ov7=0,ov8=0,ov9=0,ov10=0,saw=False,tri=False,sq=False},Dynamic[Row[{Invisible[Dynamic[EmitSound[play2[freq,time,{ov1,ov2,ov3,ov4,ov5,ov6,ov7,ov8,ov9,ov10},saw,tri,sq]],SynchronousUpdatingFalse]],Row[{Column[Graphics[Style[Disk[{1,1},1],#]]&/@{White,Black,White,Black,White,White,Black,White,Black,White,Black,White,White,Black,White,Black,White},ItemSize1,Spacings.1],VerticalSlider[Dynamic[freq],{{262,277,294,311,330,349,370,392,415,440,466,493,524,554,587,622,659}},ImageSize{30,275}]}],Column[Row[{StringJoin["Overtone ",#[[1]]],Slider[#[[2]],{0,1,.1},ContinuousActionFalse]}]&/@{{"1 ",Dynamic[ov1]},{"2 ",Dynamic[ov2]},{"3 ",Dynamic[ov3]},{"4 ",Dynamic[ov4]},{"5 ",Dynamic[ov5]},{"6 ",Dynamic[ov6]},{"7 ",Dynamic[ov7]},{"8 ",Dynamic[ov8]},{"9 ",Dynamic[ov9]},{"10",Dynamic[ov10]}},ItemSize{22,2.6}],Column[{Row[{"Saw ","Tri ","Sqr"}], Row[{Checkbox[Dynamic[saw],{False,True}], (*Checkboxes for whether each overtone should be multiplied by each wave*)Checkbox[Dynamic[tri],{False,True}],Checkbox[Dynamic[sq],{False,True}]}]},Center],Column[{"Time",VerticalSlider[Dynamic[time],{{.1,.2,.3,.5,.75,1,1.5,2}}] (*Slider to manipulate time*)}],Column[{"Quick Settings", (*Some buttons to make simple settings easy and quick to select*)Button["Single Tone",{ov1=1,ov2=0,ov3=0,ov4=0,ov5=0,ov6=0,ov7=0,ov8=0,ov9=0,ov10=0,saw=False,tri=False,sq=False}],Button["Full Harmonics",{ov1=1,ov2=1/2,ov3=1/3,ov4=1/4,ov5=1/5,ov6=1/6,ov7=1/7,ov8=1/8,ov9=1/9,ov10=1/10,saw=False,tri=False,sq=False}],Button["Odds",{ov1=1,ov2=0,ov3=1,ov4=0,ov5=1,ov6=0,ov7=1,ov8=0,ov9=1,ov10=0,saw=False,tri=False,sq=False}],Button["Evens",{ov1=0,ov2=1,ov3=0,ov4=1,ov5=0,ov6=1,ov7=0,ov8=1,ov9=0,ov10=1,saw=False,tri=False,sq=False}],Button["High",{ov1=.2,ov2=.3,ov3=.4,ov4=.5,ov5=.6,ov6=.7,ov7=.8,ov8=.9,ov9=1,ov10=1,saw=False,tri=False,sq=False}]},Center]}],SaveDefinitionsTrue,TrackedSymbols{freq}]]
Out[]=
Overtone 1 |
Overtone 2 |
Overtone 3 |
Overtone 4 |
Overtone 5 |
Overtone 6 |
Overtone 7 |
Overtone 8 |
Overtone 9 |
Overtone 10 |
Saw Tri Sqr |
Time |
Quick Settings |
Future Work
Future Work
In the future, I would like to take what I've made so far and add inharmonic overtones. This would allow it to have an exponentially wider range of timbres, and make for some very interesting sounds.