'From Squeak3.0 of 4 February 2001 [latest update: #3414] on 4 February 2001 at 7:35:03 pm'! "Change Set: SoundFixes-ar Date: 4 February 2001 Author: Andreas Raab Two fixes for the sound player. The first one makes sure we have a sound when starting the sound player which a) makes sure we don't have a pause before starting to play (important when using large buffers) and b) makes sure we're not immediately shutting down the player if the preference is set. The second fix applies to sound quick starts which now recovers gracefully if the preference is set but the VM does not support quick starts."! !SoundPlayer class methodsFor: 'snapshotting' stamp: 'ar 2/4/2001 17:59'! startUpWithSound: aSound "Start up the player process." SoundPlayer initialize. SoundPlayer startPlayerProcessBufferSize: (BufferMSecs * SamplingRate) // 1000 rate: SamplingRate stereo: Stereo sound: aSound. ! ! !SoundPlayer class methodsFor: 'playing' stamp: 'ar 2/4/2001 18:01'! resumePlaying: aSound quickStart: quickStart "Start playing the given sound without resetting it; it will resume playing from where it last stopped. If quickStart is true, then try to start playing the given sound immediately." | doQuickStart | Preferences soundsEnabled ifFalse: [^ self]. doQuickStart _ quickStart. Preferences soundQuickStart ifFalse: [doQuickStart _ false]. PlayerProcess == nil ifTrue: [ self canStartPlayer ifFalse: [^ self]. ^self startUpWithSound: aSound]. PlayerSemaphore critical: [ (ActiveSounds includes: aSound) ifTrue: [doQuickStart _ false] ifFalse: [ doQuickStart ifFalse: [ActiveSounds add: aSound]]]. "quick-start the given sound, unless the sound player has just started" doQuickStart ifTrue: [self startPlayingImmediately: aSound]. ! ! !SoundPlayer class methodsFor: 'player process' stamp: 'ar 2/4/2001 18:01'! startPlayerProcessBufferSize: bufferSize rate: samplesPerSecond stereo: stereoFlag "Start the sound player process. Terminate the old process, if any." "SoundPlayer startPlayerProcessBufferSize: 1000 rate: 11025 stereo: false" ^self startPlayerProcessBufferSize: bufferSize rate: samplesPerSecond stereo: stereoFlag sound: nil! ! !SoundPlayer class methodsFor: 'player process' stamp: 'ar 2/4/2001 18:00'! 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. aSound ifNil:[ActiveSounds _ OrderedCollection new] ifNotNil:[ActiveSounds _ OrderedCollection with: aSound]. Buffer _ SoundBuffer newStereoSampleCount: (bufferSize // 4) * 4. PlayerSemaphore _ Semaphore forMutualExclusion. SamplingRate _ samplesPerSecond. Stereo _ stereoFlag. ReadyForBuffer _ Semaphore new. SoundSupported _ true. "Assume so" UseReadySemaphore _ true. "set to false if ready semaphore not supported by VM" self primSoundStartBufferSize: Buffer stereoSampleCount rate: samplesPerSecond stereo: Stereo semaIndex: (Smalltalk registerExternalObject: ReadyForBuffer). "Check if sound start prim was successful" SoundSupported ifFalse:[^self]. UseReadySemaphore ifTrue: [PlayerProcess _ [SoundPlayer playLoop] newProcess] ifFalse: [PlayerProcess _ [SoundPlayer oldStylePlayLoop] newProcess]. UseReverb ifTrue: [self startReverb]. PlayerProcess priority: Processor userInterruptPriority. PlayerProcess resume.! ! !SoundPlayer class methodsFor: 'private' stamp: 'ar 2/4/2001 19:32'! startPlayingImmediately: aSound "Private!! Start playing the given sound as soon as possible by mixing it into the sound output buffers of the underlying sound driver." | totalSamples buf n leftover src rest | "first, fill a double-size buffer with samples" "Note: The code below assumes that totalSamples contains two buffers worth of samples, and the insertSamples primitive is expected to consume at least one buffer's worth of these samples. The remaining samples are guaranteed to fit into a single buffer." totalSamples _ Buffer stereoSampleCount * 2. "two buffer's worth" buf _ SoundBuffer newStereoSampleCount: totalSamples. aSound playSampleCount: totalSamples into: buf startingAt: 1. ReverbState == nil ifFalse: [ ReverbState applyReverbTo: buf startingAt: 1 count: totalSamples]. PlayerSemaphore critical: [ "insert as many samples as possible into the sound driver's buffers" n _ self primSoundInsertSamples: totalSamples from: buf samplesOfLeadTime: 1024. n > 0 ifTrue:[ leftover _ totalSamples - n. "copy the remainder of buf into Buffer" "Note: the following loop iterates over 16-bit words, not two-word stereo slices" "assert: 0 < leftover <= Buffer stereoSampleCount" src _ 2 * n. 1 to: 2 * leftover do: [:dst | Buffer at: dst put: (buf at: (src _ src + 1))]. "generate enough additional samples to finish filling Buffer" rest _ Buffer stereoSampleCount - leftover. aSound playSampleCount: rest into: Buffer startingAt: leftover + 1. ReverbState == nil ifFalse: [ ReverbState applyReverbTo: Buffer startingAt: leftover + 1 count: rest]. "record the fact that this sound has already been played into Buffer so that we don't process it again this time around" SoundJustStarted _ aSound. ] ifFalse:[ "quick start failed; reset the sound so we start over" aSound reset. ]. ActiveSounds add: aSound]. ! !