[squeak-dev] The Inbox: Sound-dtl.67.mcz

Levente Uzonyi leves at caesar.elte.hu
Wed Dec 11 11:32:41 UTC 2019


On Wed, 11 Dec 2019, commits at source.squeak.org wrote:

> David T. Lewis uploaded a new version of Sound to project The Inbox:
> http://source.squeak.org/inbox/Sound-dtl.67.mcz
>
> ==================== Summary ====================
>
> Name: Sound-dtl.67
> Author: dtl
> Time: 10 December 2019, 10:51:04.985835 pm
> UUID: ca970845-8428-41f9-b83c-f64a6cc732c1
> Ancestors: Sound-eem.66
>
> Sound mixing improvements by St?phane Rollandin (spfa).
> Allow adjusting volume of mixed sounds while playing.
> Original discussion at http://forum.world.st/Adjusting-the-volume-of-a-sound-as-it-s-playing-td5102562.html
> Patches posted to squeak-dev at http://lists.squeakfoundation.org/pipermail/squeak-dev/2019-December/205440.html
>
> =============== Diff against Sound-eem.66 ===============
>
> Item was changed:
>  ----- Method: AbstractSound>>loudness (in category 'volume') -----
>  loudness
>  	"Answer the current volume setting for this sound."
>
> + 	self hasVolumeEnvelope ifTrue: [^ self volumeEnvelope scale].

I don't see #hasVolumeEnvelope and #volumeEnvelope in the Trunk.

> +
> + 	^ scaledVol asFloat / ScaleFactor!
> - 	^ scaledVol asFloat / ScaleFactor asFloat!

This seems to be a place where the currently unused FloatScaleFactor 
variable could be used.

>
> Item was changed:
>  ----- Method: MixedSound>>mixSampleCount:into:startingAt:leftVol:rightVol: (in category 'sound generation') -----
>  mixSampleCount: n into: aSoundBuffer startingAt: startIndex leftVol: leftVol rightVol: rightVol
>  	"Play a number of sounds concurrently. The level of each sound can be set independently for the left and right channels."
>
>  	| snd left right |
>  	1 to: sounds size do: [:i |
>  		(soundDone at: i) ifFalse: [
>  			snd := sounds at: i.
> + 			left := (leftVol * (leftVols at: i) * scaledVol / ScaleFactor) // ScaleFactor.
> + 			right := (rightVol * (rightVols at: i) * scaledVol / ScaleFactor) // ScaleFactor.

Assuming that leftVol, rightVol are integers, and leftVols and rightVols 
are arrays of integers, #/ is very likely to introduce Fractions, and the 
triple multiplication may introduce LargeIntegers in 32-bit images.
(due to the use of #///, leftVol and rightVol are sometimes Floats, so 
the above doesn't apply for those cases).

#// may introduce noise without dithering. Perhaps it would be better to 
precalculate a constant outside the loop (e.g: scaledVol / 
FloatScaleFactor / FloatScaleFactor), and inside the loop multiply with 
that constant. I'm not an audio engineer, so I don't know if it's better 
to round than to truncate there, but truncation (as it is happening now 
via #//) will introduce some noise for sure, which could be masked by 
dithering.

> - 			left := (leftVol * (leftVols at: i)) // ScaleFactor.
> - 			right := (rightVol * (rightVols at: i)) // ScaleFactor.
>  			snd samplesRemaining > 0
>  				ifTrue: [
>  					snd mixSampleCount: n into: aSoundBuffer startingAt: startIndex leftVol: left rightVol: right]
>  				ifFalse: [soundDone at: i put: true]]].
>  !
>
> Item was changed:
>  ----- Method: RepeatingSound>>mixSampleCount:into:startingAt:leftVol:rightVol: (in category 'sound generation') -----
>  mixSampleCount: n into: aSoundBuffer startingAt: startIndex leftVol: leftVol rightVol: rightVol
>  	"Play a collection of sounds in sequence."
>  	"(RepeatingSound new
>  		setSound: FMSound majorScale
>  		iterations: 2) play"
>
>  	| i count samplesNeeded |
>  	iteration <= 0 ifTrue: [^ self].
>  	i := startIndex.
>  	samplesNeeded := n.
>  	[samplesNeeded > 0] whileTrue: [
>  		count := sound samplesRemaining min: samplesNeeded.
>  		count = 0 ifTrue: [
>  			iterationCount == #forever
>  				ifFalse: [
>  					iteration := iteration - 1.
>  					iteration <= 0 ifTrue: [^ self]].  "done"
>  			sound reset.
>  			count := sound samplesRemaining min: samplesNeeded.
>  			count = 0 ifTrue: [^ self]].  "zero length sound"
>  		sound mixSampleCount: count
>  			into: aSoundBuffer
>  			startingAt: i
> + 			leftVol: leftVol * scaledVol // ScaleFactor
> + 			rightVol: rightVol * scaledVol // ScaleFactor.

Since this method is sent with Float leftVol and rightVol arguments, 
perhaps it's worth keeping precision by not truncating to integers here 
too.

Levente

> - 			leftVol: leftVol
> - 			rightVol: rightVol.
>  		i := i + count.
>  		samplesNeeded := samplesNeeded - count].
>  !
>
> Item was changed:
>  ----- Method: SequentialSound>>mixSampleCount:into:startingAt:leftVol:rightVol: (in category 'sound generation') -----
>  mixSampleCount: n into: aSoundBuffer startingAt: startIndex leftVol: leftVol rightVol: rightVol
>  	"Play a collection of sounds in sequence."
>  	"PluckedSound chromaticScale play"
>
> + 	| finalIndex i snd remaining count leftScaledVol rightScaledVol |
> - 	| finalIndex i snd remaining count |
>  	currentIndex = 0 ifTrue: [^ self].  "already done"
> +
> + 	leftScaledVol := leftVol * scaledVol /// ScaleFactor.
> + 	rightScaledVol := rightVol * scaledVol /// ScaleFactor.
> +
>  	finalIndex := (startIndex + n) - 1.
>  	i := startIndex.
>  	[i <= finalIndex] whileTrue: [
>  		snd := (sounds at: currentIndex).
>  		[(remaining := snd samplesRemaining) <= 0] whileTrue: [
>  			"find next undone sound"
>  			currentIndex < sounds size
>  				ifTrue: [
>  					currentIndex := currentIndex + 1.
>  					snd := (sounds at: currentIndex)]
>  				ifFalse: [
>  					currentIndex := 0.
>  					^ self]].  "no more sounds"
>  		count := (finalIndex - i) + 1.
>  		remaining < count ifTrue: [count := remaining].
> + 		snd mixSampleCount: count into: aSoundBuffer startingAt: i
> + 			leftVol: leftScaledVol
> + 			rightVol: rightScaledVol.
> - 		snd mixSampleCount: count into: aSoundBuffer startingAt: i leftVol: leftVol rightVol: rightVol.
>  		i := i + count].
>  !
>
>


More information about the Squeak-dev mailing list