"The THX logo theme consists of 30 voices over seven measures, starting in a narrow range, 200 to 400 Hz, and slowly diverting to preselected pitches encompassing three octaves. The 30 voices begin at pitches between 200 Hz and 400 Hz and arrive at pre-selected pitches spanning three octaves by the fourth measure. The highest pitch is slightly detuned while there are double the number of voices of the lowest two pitches."
In[]:=
midiToHz=d|->
(d-69)/12
2
*440;
In[]:=
endMidiNotesBassTreble={{26,38,45,50,57},{62,69,74,81,86,90}};​​endFreqsBassTreble=Map[midiToHz,endMidiNotes,{2}]//N
Out[]=
{{36.7081,73.4162,110.,146.832,220.},{293.665,440.,587.33,880.,1174.66,1479.98}}
In[]:=
detuneMax=0.01;​​endFreqs=Flatten@{​​ConstantArray[endFreqsBassTreble[[1]],2],​​ConstantArray[endFreqsBassTreble[[2]],3]​​}//Map[#+(#*RandomReal[{-detuneMax,detuneMax}])&]//Sort​​endFreqs//Length
Out[]=
{36.8783,37.0043,73.6545,73.6719,109.359,109.441,145.79,146.638,221.35,222.178,291.757,292.001,296.104,437.312,437.476,442.829,585.748,589.118,589.304,874.167,883.055,885.323,1168.86,1181.36,1182.93,1469.25,1479.12,1492.01}
Out[]=
28
(I think the bass staff in the sheet music is missing a note, as the total number of voices is supposed to be 30...)
In[]:=
voiceCount=Length[endFreqs];​​freqEndPoints=Transpose[{​​RandomReal[{200,400},voiceCount],​​endFreqs​​}]
Out[]=
{{307.898,36.8783},{242.397,37.0043},{263.94,73.6545},{348.812,73.6719},{288.141,109.359},{254.283,109.441},{224.626,145.79},{368.132,146.638},{278.844,221.35},{216.767,222.178},{314.36,291.757},{380.996,292.001},{336.92,296.104},{238.896,437.312},{337.658,437.476},{221.993,442.829},{367.936,585.748},{398.342,589.118},{218.39,589.304},{274.46,874.167},{217.482,883.055},{334.134,885.323},{341.189,1168.86},{290.642,1181.36},{368.761,1182.93},{342.091,1469.25},{248.053,1479.12},{237.636,1492.01}}
In[]:=
totalLength=17;​​phase1Length=6;​​phase2Length=6;​​anchors=2;​​voiceSeries=Function[{start,end},​​TimeSeries[​​Join[​​Transpose[{​​Prepend[RandomReal[{0,phase1Length},anchors],0],​​Accumulate@Prepend[RandomReal[{-150,150},anchors],start]​​}],​​{​​{phase1Length+phase2Length,end},​​{totalLength,end}​​}​​],​​ResamplingMethod{"Interpolation",InterpolationOrder1}​​]​​]@@@freqEndPoints;
In[]:=
ListLinePlot[voiceSeries,PlotRangeAll]
Out[]=
5
10
15
500
1000
1500
In[]:=
voiceAudio=ParallelMap[AudioGenerator[{"Sin",#["PathFunction"]},totalLength]&,voiceSeries];//AbsoluteTiming
Out[]=
{14.3976,Null}
In[]:=
finalAudio=AudioOverlay[AudioAmplify[#,Quantity[15Log10[1/voiceCount],"Decibels"]]&/@voiceAudio]//AudioFade[#,{(phase1Length+phase2Length)*.8,0},Method"Exp"]&//AudioFade[#,{0,2}]&
Out[]=
00:00
00:17
Data in Notebook
In[]:=
AudioPlot[finalAudio]
Out[]=
In[]:=
Spectrogram[finalAudio,PlotRange{0,2000}]
Out[]=