Object subclass: #SineWaveGenerator instanceVariableNames: 'step current initialPhase ' classVariableNames: '' poolDictionaries: '' category: 'Sound-Waves'! !SineWaveGenerator methodsFor: 'initialize' stamp: 'tf 7/25/2002 21:25'! initialPhase:phase initialPhase _ phase.! ! !SineWaveGenerator methodsFor: 'initialize' stamp: 'tf 7/27/2002 21:28'! initialize initialPhase _ 0.0. step _ 1.0. current _ initialPhase.! ! !SineWaveGenerator methodsFor: 'initialize' stamp: 'tf 7/25/2002 21:25'! oneCycle:oneCycle step _ (360 /oneCycle) asFloat. ! ! !SineWaveGenerator methodsFor: 'initialize' stamp: 'tf 7/25/2002 21:24'! step:aStep step _ aStep.! ! !SineWaveGenerator methodsFor: 'accessing' stamp: 'tf 7/25/2002 21:28'! initialPhase ^initialPhase! ! !SineWaveGenerator methodsFor: 'accessing' stamp: 'tf 7/27/2002 21:29'! next | ans | ans _ (current degreeSin). current _ current + step. (current >= 360) ifTrue:[ current _ current \\ 360. ]. ^ans.! ! !SineWaveGenerator methodsFor: 'accessing' stamp: 'tf 7/25/2002 21:28'! oneCycle ^360.0 / step.! ! !SineWaveGenerator methodsFor: 'accessing' stamp: 'tf 7/25/2002 22:17'! reset current _ initialPhase.! ! !SineWaveGenerator methodsFor: 'accessing' stamp: 'tf 7/25/2002 21:28'! step ^step.! ! !SineWaveGenerator methodsFor: 'testing' stamp: 'tf 7/25/2002 22:22'! showOnDisplay | xOrigin yOrigin y | xOrigin _ 30. yOrigin _ 130. self reset. Display fillBlack: (xOrigin@(yOrigin - 100) extent: 1@100). xOrigin to:(xOrigin + 200) do:[ :x | y _ (self next * 100.0) + yOrigin. Display fillBlack: ((x - 1)@(y - 1) extent: 2@2). Display fillBlack: (x@yOrigin extent: 1@1). x _ x + 1 ]. ! ! "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "! SineWaveGenerator class instanceVariableNames: ''! !SineWaveGenerator class methodsFor: 'examples' stamp: 'tf 7/25/2002 21:30'! example1 | tmp | tmp _ self new initialize. tmp oneCycle:20. 22 timesRepeat:[ Transcript show:(tmp next printString); cr. ]. ! ! !SineWaveGenerator class methodsFor: 'examples' stamp: 'tf 7/27/2002 21:30'! example2 (SineWaveGenerator new initialize oneCycle:100.0) showOnDisplay. ! ! Object subclass: #SoundEnvelope instanceVariableNames: 'points samplingRate current ' classVariableNames: '' poolDictionaries: '' category: 'Sound-Waves'! !SoundEnvelope methodsFor: 'initialize' stamp: 'tf 7/27/2002 00:11'! points:aPoints points _ aPoints.! ! !SoundEnvelope methodsFor: 'initialize' stamp: 'tf 7/27/2002 00:12'! samplingRate:aSamplingRate samplingRate _ aSamplingRate.! ! !SoundEnvelope methodsFor: 'accessing' stamp: 'tf 7/27/2002 21:55'! next | pos value | 1 to:(points size) do:[ :i | pos _ (points at:i) x. (pos >= current) ifTrue:[ (pos = current) ifTrue:[ current _ current + 1. ^((points at:i) y) asFloat. ]. (i = 1) ifTrue:[ current _ current + 1. ^0.0. ]. (((points at:(points size)) x) < current) ifTrue:[ ^0.0. ]. value _ self valueAt:current between:(i - 1) and:i. current _ current + 1. ^value. ]. ]. ^0.0. ! ! !SoundEnvelope methodsFor: 'accessing' stamp: 'tf 7/27/2002 00:12'! reset current _ 0. ! ! !SoundEnvelope methodsFor: 'private' stamp: 'tf 7/27/2002 21:55'! valueAt:pos between:sIndex and:eIndex | sPos ePos ratio sValue eValue | sPos _ (points at:sIndex) x. ePos _ (points at:eIndex) x. ratio _ (ePos - sPos) / (pos - sPos). sValue _ (points at:sIndex) y. eValue _ (points at:eIndex) y. ^((eValue - sValue) / ratio) + sValue.! ! !SoundEnvelope methodsFor: 'testing' stamp: 'tf 7/27/2002 21:54'! atEnd ^(current >= ((points at:(points size)) x)).! ! "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "! SoundEnvelope class instanceVariableNames: ''! !SoundEnvelope class methodsFor: 'instance creation' stamp: 'tf 7/27/2002 00:13'! new:points | tmp | tmp _ super new. tmp points:points; samplingRate:44100; reset. ^tmp. ! ! !SoundEnvelope class methodsFor: 'testing' stamp: 'tf 7/27/2002 22:00'! showOnDisplay | xOrigin yOrigin y tmp x | xOrigin _ 30. yOrigin _ 130. tmp _ self new:{ 0@0 . 20@1 . 50@0.5 . 80@0.8 . 150@0}. Display fillBlack: (xOrigin@(yOrigin - 100) extent: 1@100). x _ xOrigin. [tmp atEnd] whileFalse:[ y _ (tmp next * -100.0) + yOrigin. Display fillBlack: ((x - 1)@(y - 1) extent: 2@2). Display fillBlack: (x@yOrigin extent: 1@1). x _ x + 1 ]. ! ! Object subclass: #SoundWaveGenerator instanceVariableNames: 'waveSources pitch samplingRate phase magnitude ' classVariableNames: 'HighestPitch LowestPitch ' poolDictionaries: '' category: 'Sound-Waves'! !SoundWaveGenerator methodsFor: 'initialize' stamp: 'tf 7/25/2002 00:49'! defaultMagnitude magnitude _ Array new:(waveSources size). magnitude at:1 put:1.0. 2 to:(magnitude size) do:[ :i | magnitude at:i put:0.0. ]. ! ! !SoundWaveGenerator methodsFor: 'initialize' stamp: 'tf 7/26/2002 23:06'! defaultNumberOfSources | freq | pitch ifNil:[ pitch _ 440. ]. freq _ pitch. 1 to:100 do:[ :n | (freq > self class highestPitch) ifTrue:[ self numberOfSources:n. ^self. ]. freq _ freq * freq. ]. ! ! !SoundWaveGenerator methodsFor: 'initialize' stamp: 'tf 7/25/2002 21:32'! defaultPhase phase _ Array new:(waveSources size). 1 to:(waveSources size) do:[ :i | phase at:i put:0.0. ]. ! ! !SoundWaveGenerator methodsFor: 'initialize' stamp: 'tf 7/26/2002 23:01'! initialize self samplingRate:44100.0. "use 44.1kHz" self pitch:440.0. "use 440Hz" self defaultNumberOfSources. self defaultPhase. self defaultMagnitude. self makeReady. ! ! !SoundWaveGenerator methodsFor: 'initialize' stamp: 'tf 7/25/2002 00:50'! magnitude:magnitudeArray ((magnitudeArray size) = (waveSources size)) ifFalse:[ self error:'magnitudeArray size AND waveSource size MUST BE THE SAME'. ^nil. ]. magnitude _ magnitudeArray. ! ! !SoundWaveGenerator methodsFor: 'initialize' stamp: 'tf 7/27/2002 21:32'! makeReady | sampleCount | sampleCount _ samplingRate / pitch. 1 to:(waveSources size) do:[ :i | (waveSources at:i) oneCycle:(sampleCount / i). (waveSources at:i) initialPhase:(phase at:i). (waveSources at:i) reset. ]. ! ! !SoundWaveGenerator methodsFor: 'initialize' stamp: 'tf 7/27/2002 21:33'! numberOfSources:aInteger waveSources _ Array new:aInteger. 1 to:aInteger do:[ :i | waveSources at:i put:(SineWaveGenerator new initialize). ]. ! ! !SoundWaveGenerator methodsFor: 'initialize' stamp: 'tf 7/25/2002 00:46'! phase:phaseArray ((phaseArray size) = (waveSources size)) ifFalse:[ self error:'phaseArray size AND waveSource size MUST BE THE SAME'. ^nil. ]. phase _ phaseArray. ! ! !SoundWaveGenerator methodsFor: 'initialize' stamp: 'tf 7/25/2002 00:50'! pitch:aHz pitch _ aHz. ! ! !SoundWaveGenerator methodsFor: 'initialize' stamp: 'tf 7/25/2002 00:51'! samplingRate:aSamplingRate samplingRate _ aSamplingRate. ! ! !SoundWaveGenerator methodsFor: 'accessing' stamp: 'tf 7/27/2002 21:35'! next | array value | array _ self nextArray. value _ 0.0. 1 to:(array size) do:[ :i | value _ value + (array at:i). ]. ^value.! ! !SoundWaveGenerator methodsFor: 'accessing' stamp: 'tf 7/25/2002 00:42'! numberOfSources ^waveSources size. ! ! !SoundWaveGenerator methodsFor: 'private' stamp: 'tf 7/25/2002 01:23'! nextArray | array | array _ Array new:(waveSources size). 1 to:(waveSources size) do:[ :i | array at:i put:(((waveSources at:i) next) * (magnitude at:i)). ]. ^array.! ! !SoundWaveGenerator methodsFor: 'testing' stamp: 'tf 7/27/2002 21:40'! showOnDisplay | xOrigin yOrigin y sine mag | xOrigin _ 30. yOrigin _ 130. Display fillBlack: (xOrigin@(yOrigin - 100) extent: 1@100). 1 to:(waveSources size) do:[ :i | sine _ waveSources at:i. sine reset. mag _ magnitude at:i. xOrigin to:(xOrigin + 400) do:[ :x | y _ (sine next * mag * 100.0) + yOrigin. Display fillBlack: ((x - 1)@(y - 1) extent: 2@2). Display fillBlack: (x@yOrigin extent: 1@1). x _ x + 1 ]. ]. ! ! "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "! SoundWaveGenerator class instanceVariableNames: ''! !SoundWaveGenerator class methodsFor: 'initialize' stamp: 'tf 7/26/2002 23:05'! initialize LowestPitch _ 20.0. HighestPitch _ 20000.0. ! ! !SoundWaveGenerator class methodsFor: 'instance creation' stamp: 'tf 7/25/2002 01:17'! new | tmp | tmp _ super new. tmp initialize. ^tmp.! ! !SoundWaveGenerator class methodsFor: 'testing' stamp: 'tf 7/27/2002 21:36'! test1 | tmp | tmp _ self new. tmp numberOfSources:5; phase:#(0 90 180 270 0); magnitude:#(1.0 0.5 0.3 0.2 0.1); makeReady. 20 timesRepeat:[ Transcript show:(tmp nextArray printString); cr. ]. ! ! !SoundWaveGenerator class methodsFor: 'testing' stamp: 'tf 7/27/2002 21:47'! test2 | tmp output seconds samplingRate duration waveEditor | Transcript show:'test2 started....'. duration _ Time millisecondsToRun:[ tmp _ self new. samplingRate _ 44100. tmp numberOfSources:12; phase:#(0 90 180 270 0 90 180 270 0 90 180 270); magnitude:#(1.0 0.5 0.3 0.2 0.1 0.05 0.04 0.03 0.02 0.01 0.005 0.002); pitch:440; samplingRate:samplingRate; makeReady. seconds _ 5. output _ Array new:(seconds * samplingRate). 1 to:(seconds * samplingRate) do:[ :i | output at:i put:(tmp next * 10000.0). ]. ]. Transcript show:' it took ', (duration // 1000) printString, ' seconds.' ; cr. "WaveEditor openOn:output." waveEditor _ WaveEditor new initialize. waveEditor samplingRate:44100; data:output; openInWorld. ! ! !SoundWaveGenerator class methodsFor: 'testing' stamp: 'tf 7/27/2002 21:41'! test3 | tmp | tmp _ self new. tmp numberOfSources:5; phase:#(0.0 0.0 0.0 0.0 0.0); magnitude:#(1.0 0.8 0.7 0.6 0.5); makeReady. tmp showOnDisplay. ! ! !SoundWaveGenerator class methodsFor: 'accessing' stamp: 'tf 7/26/2002 23:05'! highestPitch ^HighestPitch.! ! !SoundWaveGenerator class methodsFor: 'accessing' stamp: 'tf 7/26/2002 23:05'! lowestPitch ^LowestPitch.! ! SoundWaveGenerator initialize!