Eliot Miranda uploaded a new version of Sound to project The Trunk: http://source.squeak.org/trunk/Sound-eem.74.mcz
==================== Summary ====================
Name: Sound-eem.74 Author: eem Time: 19 September 2020, 9:11:40.666386 am UUID: 42a3c2d9-0bed-4310-bcf1-cbe0f3d0653b Ancestors: Sound-eem.73
Oops! stopPlayerProcess *must* stop the sound system when sent from startPlayerProcessBufferSize:rate:stereo:sound:. Spo refactor a bit, renaming stopPlayerProcess to stopPlayerProcess: to take a hardStop boolean. When quitting the argument is false.
Add a 64-bit specific, integer-overflow agnostic version of mixSampleCount:into:startingAt:leftVol:rightVol:, for creating a simpler inline primitive in the 64-bit VM.
=============== Diff against Sound-eem.73 ===============
Item was changed: ----- Method: AbstractSound class>>translatedPrimitives (in category 'primitive generation') ----- translatedPrimitives ^#( (FMSound mixSampleCount:into:startingAt:leftVol:rightVol:) (PluckedSound mixSampleCount:into:startingAt:leftVol:rightVol:) (LoopedSampledSound mixSampleCount:into:startingAt:leftVol:rightVol:) (SampledSound mixSampleCount:into:startingAt:leftVol:rightVol:) + (SampledSound _64bitMixSampleCount:into:startingAt:leftVol:rightVol:) (ReverbSound applyReverbTo:startingAt:count:) ). !
Item was added: + ----- Method: SampledSound>>_64bitMixSampleCount:into:startingAt:leftVol:rightVol: (in category 'playing') ----- + _64bitMixSampleCount: n into: aSoundBuffer startingAt: startIndex leftVol: leftVol rightVol: rightVol + "Mix the given number of samples with the samples already in the given buffer starting at the given index. + Assume that the buffer size is at least (index + count) - 1." + + | lastIndex outIndex sampleIndex sample i s | + <inline: #always> + <var: #aSoundBuffer type: #'short int *'> + <var: #samples type: #'short int *'> + + lastIndex := (startIndex + n) - 1. + outIndex := startIndex. "index of next stereo output sample pair" + sampleIndex := indexHighBits + (scaledIndex >> IncrementFractionBits). + [(sampleIndex <= samplesSize) and: [outIndex <= lastIndex]] whileTrue: + [sample := ((samples at: sampleIndex) * scaledVol) // ScaleFactor. + leftVol > 0 ifTrue: + [i := (2 * outIndex) - 1. + s := (aSoundBuffer at: i) + ((sample * leftVol) // ScaleFactor). + s > 32767 ifTrue: [s := 32767]. "clipping!!" + s < -32767 ifTrue: [s := -32767]. "clipping!!" + aSoundBuffer at: i put: s]. + rightVol > 0 ifTrue: + [i := 2 * outIndex. + s := (aSoundBuffer at: i) + ((sample * rightVol) // ScaleFactor). + s > 32767 ifTrue: [s := 32767]. "clipping!!" + s < -32767 ifTrue: [s := -32767]. "clipping!!" + aSoundBuffer at: i put: s]. + + scaledVolIncr ~= 0 ifTrue: + [scaledVol := scaledVol + scaledVolIncr. + ((scaledVolIncr > 0 and: [scaledVol >= scaledVolLimit]) or: + [scaledVolIncr < 0 and: [scaledVol <= scaledVolLimit]]) + ifTrue: "reached the limit; stop incrementing" + [scaledVol := scaledVolLimit. + scaledVolIncr := 0]]. + + scaledIndex := scaledIndex + scaledIncrement. + + sampleIndex := indexHighBits + (scaledIndex >> IncrementFractionBits). + outIndex := outIndex + 1]. + count := count - n + !
Item was changed: ----- Method: SampledSound>>mixSampleCount:into:startingAt:leftVol:rightVol: (in category 'playing') ----- mixSampleCount: n into: aSoundBuffer startingAt: startIndex leftVol: leftVol rightVol: rightVol + "Mix the given number of samples with the samples already in the given buffer starting at the given index. + Assume that the buffer size is at least (index + count) - 1." - "Mix the given number of samples with the samples already in the given buffer starting at the given index. Assume that the buffer size is at least (index + count) - 1."
| lastIndex outIndex sampleIndex sample i s overflow | + <primitive:'primitiveMixSampledSound' module: 'SoundGenerationPlugin'> + <var: #aSoundBuffer type: #'short int *'> + <var: #samples type: #'short int *'> - <primitive:'primitiveMixSampledSound' module:'SoundGenerationPlugin'> - <var: #aSoundBuffer declareC: 'short int *aSoundBuffer'> - <var: #samples declareC: 'short int *samples'>
+ SmallInteger maxVal > 16r3FFFFFFF ifTrue: "In 64-bits we don't have to worry about 2^15 * 2^15 overflow" + [^self _64bitMixSampleCount: n into: aSoundBuffer startingAt: startIndex leftVol: leftVol rightVol: rightVol]. lastIndex := (startIndex + n) - 1. outIndex := startIndex. "index of next stereo output sample pair" sampleIndex := indexHighBits + (scaledIndex >> IncrementFractionBits). [(sampleIndex <= samplesSize) and: [outIndex <= lastIndex]] whileTrue: [ sample := ((samples at: sampleIndex) * scaledVol) // ScaleFactor. leftVol > 0 ifTrue: [ i := (2 * outIndex) - 1. s := (aSoundBuffer at: i) + ((sample * leftVol) // ScaleFactor). s > 32767 ifTrue: [s := 32767]. "clipping!!" s < -32767 ifTrue: [s := -32767]. "clipping!!" aSoundBuffer at: i put: s]. rightVol > 0 ifTrue: [ i := 2 * outIndex. s := (aSoundBuffer at: i) + ((sample * rightVol) // ScaleFactor). s > 32767 ifTrue: [s := 32767]. "clipping!!" s < -32767 ifTrue: [s := -32767]. "clipping!!" aSoundBuffer at: i put: s].
scaledVolIncr ~= 0 ifTrue: [ scaledVol := scaledVol + scaledVolIncr. ((scaledVolIncr > 0 and: [scaledVol >= scaledVolLimit]) or: [scaledVolIncr < 0 and: [scaledVol <= scaledVolLimit]]) ifTrue: [ "reached the limit; stop incrementing" scaledVol := scaledVolLimit. scaledVolIncr := 0]].
scaledIndex := scaledIndex + scaledIncrement. scaledIndex >= ScaledIndexOverflow ifTrue: [ overflow := scaledIndex >> IncrementFractionBits. indexHighBits := indexHighBits + overflow. scaledIndex := scaledIndex - (overflow << IncrementFractionBits)].
sampleIndex := indexHighBits + (scaledIndex >> IncrementFractionBits). outIndex := outIndex + 1]. + count := count - n! - count := count - n. - !
Item was changed: ----- Method: SoundPlayer class>>shutDown: (in category 'snapshotting') ----- shutDown: quitting "Stop player process, for example before snapshotting."
+ quitting ifTrue: + [self stopPlayerProcess: false. + ReverbState := nil]! - quitting ifTrue: [ - self stopPlayerProcess. - ReverbState := nil].!
Item was changed: ----- Method: SoundPlayer class>>startPlayerProcessBufferSize:rate:stereo:sound: (in category 'player process') ----- startPlayerProcessBufferSize: bufferSize rate: samplesPerSecond stereo: stereoFlag sound: aSound "Start the sound player process. Terminate the old process, if any." "SoundPlayer startPlayerProcessBufferSize: 1000 rate: 11025 stereo: false"
+ self stopPlayerProcess: true. + aSound ifNotNil: "stopPlayerProcess: ensures ActiveSounds are empty..." + [ActiveSounds add: aSound]. - self stopPlayerProcess. - aSound - ifNil:[ActiveSounds := OrderedCollection new] - ifNotNil:[ActiveSounds := OrderedCollection with: aSound]. Buffer := SoundBuffer newStereoSampleCount: (bufferSize // 4) * 4. + LastBuffer ifNotNil: + [LastBuffer := SoundBuffer basicNew: Buffer basicSize]. - LastBuffer ifNotNil:[LastBuffer := SoundBuffer basicNew: Buffer basicSize]. PlayerSemaphore := Semaphore forMutualExclusion. SamplingRate := samplesPerSecond. Stereo := stereoFlag. SoundSupported := true. "Assume so" UseReadySemaphore := true. "set to false if ready semaphore not supported by VM" Smalltalk newExternalSemaphoreDo: [ :semaphore :index | ReadyForBuffer := semaphore. self primSoundStartBufferSize: Buffer stereoSampleCount rate: samplesPerSecond stereo: Stereo semaIndex: index ]. "Check if sound start prim was successful" SoundSupported ifFalse:[ Smalltalk unregisterExternalObject: ReadyForBuffer. ReadyForBuffer := nil. ^self ]. UseReadySemaphore ifTrue: [PlayerProcess := [SoundPlayer playLoop] newProcess] ifFalse: [PlayerProcess := [SoundPlayer oldStylePlayLoop] newProcess]. UseReverb ifTrue: [self startReverb].
PlayerProcess name: 'Sound Player (', ActiveSounds size asString, ')'; priority: Processor userInterruptPriority; resume!
Item was removed: - ----- Method: SoundPlayer class>>stopPlayerProcess (in category 'player process') ----- - stopPlayerProcess - "Stop the sound player process." - "SoundPlayer stopPlayerProcess" - - PlayerProcess ifNotNil: - [PlayerProcess ~~ Processor activeProcess ifTrue: - [PlayerProcess terminate]. - PlayerProcess := nil]. - "Don't load the SoundPlugin if it is not in use..." - self soundPluginActive ifTrue: [self primSoundStop]. - ActiveSounds isEmpty ifFalse: - [ActiveSounds := OrderedCollection new]. - Buffer := nil. - PlayerSemaphore isEmpty ifFalse: - [PlayerSemaphore := Semaphore forMutualExclusion]. - ReadyForBuffer ifNotNil: - [Smalltalk unregisterExternalObject: ReadyForBuffer. - ReadyForBuffer := nil]!
Item was added: + ----- Method: SoundPlayer class>>stopPlayerProcess: (in category 'player process') ----- + stopPlayerProcess: hardStop + "Stop the sound player process." + "SoundPlayer stopPlayerProcess" + + PlayerProcess ifNotNil: + [PlayerProcess ~~ Processor activeProcess ifTrue: + [PlayerProcess terminate]. + PlayerProcess := nil]. + (hardStop or: [self soundPluginActive]) ifTrue: [self primSoundStop]. + ActiveSounds isEmpty ifFalse: + [ActiveSounds := OrderedCollection new]. + Buffer := nil. + PlayerSemaphore isEmpty ifFalse: + [PlayerSemaphore := Semaphore forMutualExclusion]. + ReadyForBuffer ifNotNil: + [Smalltalk unregisterExternalObject: ReadyForBuffer. + ReadyForBuffer := nil]!
packages@lists.squeakfoundation.org