'From Squeak3.7alpha of 11 September 2003 [latest update: #5741] on 2 March 2004 at 4:57 pm'! !ADPCMCodec commentStamp: '' prior: 0! This is a simple ADPCM (adapative delta pulse code modulation) codec. This is a general audio codec that compresses speech, music, or sound effects equally well, and works at any sampling rate (i.e., it contains no frequency-sensitive filters). It compresses 16-bit sample data down to 5, 4, 3, or 2 bits per sample, with lower fidelity and increased noise at the lowest bit rates. Although it does not deliver state-of-the-art compressions, the algorithm is small, simple, and extremely fast, since the encode/decode primitives have been translated into C primitives. This codec will also encode and decode all Flash .swf file compressed sound formats, both mono and stereo. (Note: stereo Flash compression is not yet implemented, but stereo decompression works.) ! !PianoRollScoreMorph commentStamp: '' prior: 0! A PianoRollScoreMorph displays a score such as a MIDIScore, and will scroll through it tracking the progress of a ScorePlayerMorph (from which it is usually spawned). timeScale is in pixels per score tick. Currently the ambient track (for synchronizing thumbnails, eg) is treated specially here and in the score. This should be cleaned up by adding a trackType or something like it in the score.! !ADPCMCodec methodsFor: 'private' stamp: 'zz 3/2/2004 07:58'! indexForDeltaFrom: thisSample to: nextSample "Answer the best index to use for the difference between the given samples." "Details: Scan stepSizeTable for the first entry >= the absolute value of the difference between sample values. Since indexes are zero-based, the index used during decoding will be the one in the following stepSizeTable entry. Since the index field of a Flash frame header is only six bits, the maximum index value is 63." "Note: Since there does not appear to be any documentation of how Flash actually computes the indices used in its frame headers, this algorithm was guessed by reverse-engineering the Flash ADPCM decoder." | diff bestIndex | self inline: true. diff _ nextSample - thisSample. diff < 0 ifTrue: [diff _ 0 - diff]. bestIndex _ 63. 1 to: 62 do: [:j | bestIndex = 63 ifTrue: [ (stepSizeTable at: j) >= diff ifTrue: [bestIndex _ j]]]. ^ bestIndex ! ! !FWT methodsFor: 'access' stamp: 'zz 3/2/2004 08:13'! coeffs "Return all coefficients needed to reconstruct the original samples" | header csize strm | header _ Array with: nSamples with: nLevels with: alpha with: beta. csize _ header size. 1 to: nLevels do: [:i | csize _ csize + (transform at: i*2) size]. csize _ csize + (transform at: nLevels*2-1) size. coeffs _ Array new: csize. strm _ WriteStream on: coeffs. strm nextPutAll: header. 1 to: nLevels do: [:i | strm nextPutAll: (transform at: i*2)]. strm nextPutAll: (transform at: nLevels*2-1). ^ coeffs! ! !LoopedSampledSound methodsFor: 'accessing' stamp: 'zz 3/2/2004 08:18'! samples "For compatibility with SampledSound. Just return my left channel (which is the only channel if I am mono)." ^ leftSamples ! ! !ReverbSound methodsFor: 'sound generation' stamp: 'zz 3/2/2004 08:26'! mixSampleCount: n into: aSoundBuffer startingAt: startIndex leftVol: leftVol rightVol: rightVol "Play my sound with reverberation." sound mixSampleCount: n into: aSoundBuffer startingAt: startIndex leftVol: leftVol rightVol: rightVol. self applyReverbTo: aSoundBuffer startingAt: startIndex count: n. ! ! !ScorePlayer methodsFor: 'sound generation' stamp: 'zz 3/2/2004 16:45'! jumpToTick: startTick self reset. self processTempoMapAtTick: startTick. self skipNoteEventsThruTick: startTick. self skipAmbientEventsThruTick: startTick. ticksSinceStart _ startTick. ! ! !SoundBuffer class methodsFor: 'objects from disk' stamp: 'zz 3/2/2004 08:34'! startUpFrom: anImageSegment "In this case, do we need to swap word halves when reading this segment?" ^ (Smalltalk endianness) ~~ (anImageSegment endianness) ifTrue: [Message selector: #swapHalves] "will be run on each instance" ifFalse: [nil].! !