'From etoys3.0 of 24 February 2008 [latest update: #2052] on 28 July 2008 at 1:33:19 pm'! "Change Set: WSRework-yo Date: 28 July 2008 Author: Yoshiki Ohshima Fix analog/direct input mode. "! ImageMorph subclass: #WsGraphMorph instanceVariableNames: 'graphType dataType model data dataColor cursor cursorColor cursorColorAtZeroCrossings startIndex relativeScale minVal maxVal imageFormValid' classVariableNames: '' poolDictionaries: '' category: 'WS-Sound-Interface'! WsGraphMorph subclass: #WsSignalGraphMorph instanceVariableNames: 'capacity mouseDown' classVariableNames: '' poolDictionaries: '' category: 'WS-Sound-Interface'! ImageMorph subclass: #WsSonogram instanceVariableNames: 'model dataColor lastX scrollDelta pixValMap allOne words' classVariableNames: '' poolDictionaries: '' category: 'WS-Sound-Interface'! Object subclass: #WsWorldStethoscope instanceVariableNames: 'soundInput fft sounds offset cutOffLevel sortType listening passOver passUnder rangeFinderMode recordedCount views passMask biasInput totalSamples nextUpdateInGiga directInputMode nextUpdate wantsToRecord updateIntervalInSec totalSamplesInGiga representativeData ' classVariableNames: '' poolDictionaries: '' category: 'WS-Sound-Interface'! AlignmentMorph subclass: #WsWorldStethoscopeMorph instanceVariableNames: 'statusLight model directModeLight biasModeLight ' classVariableNames: '' poolDictionaries: '' category: 'WS-Sound-Interface'! !ByteArray methodsFor: '*Tweak-Kedama' stamp: 'yo 7/14/2008 22:02'! bytesOr: aByteArray "^ KedamaPlugin2 doPrimitive: #primitiveOrByteArray." 1 to: (self size min: aByteArray size) do: [:i | self at: i put: (((self at: i) + (aByteArray at: i)) > 0 ifTrue: [1] ifFalse: [0]). ]. ! ! !FFT methodsFor: 'bulk processing' stamp: 'yo 7/12/2008 08:37'! transformDataFrom: anIndexableCollection startingAt: index "Forward transform a block of real data taken from from the given indexable collection starting at the given index. Answer a block of values representing the normalized magnitudes of the frequency components." | j real imag out | j _ 0. index to: index + n - 1 do: [:i | realData at: (j _ j + 1) put: (anIndexableCollection at: i)]. realData *= window. imagData _ FloatArray new: n. self pluginTransformData: true. "compute the magnitudes of the complex results" "note: the results are in bottom half; the upper half is just its mirror image" real _ realData copyFrom: 1 to: (n / 2). imag _ imagData copyFrom: 1 to: (n / 2). out _ (real *= real) += (imag *= imag). 1 to: out size do: [:i | out at: i put: (out at: i) sqrt]. ^ out ! ! !Player methodsFor: 'slot getters/setters' stamp: 'yo 7/16/2008 15:24'! getRelativeScale ^ costume relativeScale ! ! !Player methodsFor: 'slot getters/setters' stamp: 'yo 7/16/2008 15:24'! setRelativeScale: aBoolean costume relativeScale: aBoolean! ! !Player methodsFor: '*WS-Sound-Interface' stamp: 'yo 7/16/2008 15:25'! getDataColor ^ costume dataColor ! ! !Player methodsFor: '*WS-Sound-Interface' stamp: 'yo 7/16/2008 15:24'! getDirectModeReadOut ^ costume directModeReadOut ! ! !Player methodsFor: '*WS-Sound-Interface' stamp: 'yo 7/16/2008 15:27'! getScrollDelta ^ costume scrollDelta ! ! !Player methodsFor: '*WS-Sound-Interface' stamp: 'yo 7/16/2008 15:24'! getUpdateInterval ^ costume updateInterval! ! !Player methodsFor: '*WS-Sound-Interface' stamp: 'yo 7/16/2008 15:25'! setDataColor: aColor costume dataColor: aColor! ! !Player methodsFor: '*WS-Sound-Interface' stamp: 'yo 7/16/2008 15:27'! setScrollDelta: aNumber ^ costume scrollDelta: aNumber ! ! !Player methodsFor: '*WS-Sound-Interface' stamp: 'yo 7/16/2008 15:24'! setUpdateInterval: aNumber costume updateInterval: aNumber! ! !SoundRecorder methodsFor: 'primitives' stamp: 'yo 7/16/2008 12:00'! primGetSwitch: id captureFlag: capture channel: channel ^ -1! ! !SoundRecorder methodsFor: 'primitives' stamp: 'yo 7/16/2008 12:00'! primSetDevice: anInteger name: aString ^ -1. ! ! !SoundRecorder methodsFor: 'primitives' stamp: 'yo 7/16/2008 12:00'! primSetSwitch: id captureFlag: capture parameter: parameter ^ -1! ! !WsGraphMorph methodsFor: 'accessing' stamp: 'yo 7/14/2008 23:57'! color ^ color ! ! !WsGraphMorph methodsFor: 'accessing' stamp: 'yo 7/14/2008 23:57'! color: aColor color _ aColor. self flushCachedForm. ! ! !WsGraphMorph methodsFor: 'accessing' stamp: 'yo 7/12/2008 13:59'! cursorAtEnd ^ cursor truncated >= data size ! ! !WsGraphMorph methodsFor: 'accessing' stamp: 'yo 7/12/2008 13:59'! cursorColor ^ cursorColor ! ! !WsGraphMorph methodsFor: 'accessing' stamp: 'yo 7/12/2008 13:59'! cursorColorAtZeroCrossing ^ cursorColorAtZeroCrossings ! ! !WsGraphMorph methodsFor: 'accessing' stamp: 'yo 7/12/2008 13:59'! cursorColorAtZeroCrossings: aColor cursorColorAtZeroCrossings _ aColor. self flushCachedForm. ! ! !WsGraphMorph methodsFor: 'accessing' stamp: 'yo 7/12/2008 13:59'! cursorColor: aColor cursorColor _ aColor. self flushCachedForm. ! ! !WsGraphMorph methodsFor: 'accessing' stamp: 'yo 7/16/2008 10:40'! cursorWrapped: aNumber | sz | cursor ~= aNumber ifTrue: [ cursor _ aNumber. sz _ data size. sz = 0 ifTrue: [cursor _ 1] ifFalse: [ ((cursor >= (sz + 1)) or: [cursor < 0]) ifTrue: [ cursor _ cursor - ((cursor // sz) * sz)]. cursor < 1 ifTrue: [cursor _ sz + cursor]]. "assert: 1 <= cursor < data size + 1" ]. ! ! !WsGraphMorph methodsFor: 'accessing' stamp: 'yo 7/12/2008 13:59'! data ^ data ! ! !WsGraphMorph methodsFor: 'accessing' stamp: 'yo 7/12/2008 13:59'! dataColor ^ dataColor ! ! !WsGraphMorph methodsFor: 'accessing' stamp: 'yo 7/12/2008 13:59'! dataColor: aColor dataColor _ aColor. self flushCachedForm. ! ! !WsGraphMorph methodsFor: 'accessing' stamp: 'yo 7/15/2008 10:10'! dataType: aSymbol dataType _ aSymbol. self resetTo: self extent. ! ! !WsGraphMorph methodsFor: 'accessing' stamp: 'yo 7/14/2008 22:59'! data: aCollection data _ aCollection. relativeScale ifTrue: [ data do: [:x | x < minVal ifTrue: [minVal _ x]. x > maxVal ifTrue: [maxVal _ x]]]. self flushCachedForm. ! ! !WsGraphMorph methodsFor: 'accessing' stamp: 'yo 7/15/2008 00:08'! extent: aPoint self resetTo: aPoint. ! ! !WsGraphMorph methodsFor: 'accessing' stamp: 'yo 7/15/2008 00:09'! graphType: aSymbol graphType _ aSymbol. self resetTo: self extent. ! ! !WsGraphMorph methodsFor: 'accessing' stamp: 'yo 7/12/2008 13:59'! interpolatedValueAtCursor | sz prev frac next | data isEmpty ifTrue: [^0]. sz := data size. cursor < 0 ifTrue: [^data first]. "just to be safe, though cursor shouldn't be negative" prev := cursor truncated. frac := cursor - prev. prev < 1 ifTrue: [prev := sz]. prev > sz ifTrue: [prev := 1]. "assert: 1 <= prev <= sz" frac = 0 ifTrue: [^data at: prev]. "no interpolation needed" "interpolate" next := prev = sz ifTrue: [1] ifFalse: [prev + 1]. ^(1.0 - frac) * (data at: prev) + (frac * (data at: next))! ! !WsGraphMorph methodsFor: 'accessing' stamp: 'yo 7/12/2008 13:59'! lastValue data isEmpty ifTrue: [^0]. ^data last! ! !WsGraphMorph methodsFor: 'accessing' stamp: 'yo 7/12/2008 13:59'! lastValue: aNumber self appendValue: aNumber. ! ! !WsGraphMorph methodsFor: 'accessing' stamp: 'yo 7/14/2008 19:55'! maxVal ^ maxVal ! ! !WsGraphMorph methodsFor: 'accessing' stamp: 'yo 7/16/2008 10:39'! maxVal: aNumber maxVal _ aNumber. self flushCachedForm. ! ! !WsGraphMorph methodsFor: 'accessing' stamp: 'yo 7/14/2008 19:55'! minVal ^ minVal ! ! !WsGraphMorph methodsFor: 'accessing' stamp: 'yo 7/14/2008 19:55'! minVal: aNumber minVal _ aNumber. ! ! !WsGraphMorph methodsFor: 'accessing' stamp: 'yo 7/15/2008 00:00'! model: anObject model _ anObject. ! ! !WsGraphMorph methodsFor: 'accessing' stamp: 'yo 7/14/2008 22:54'! relativeScale ^ relativeScale ! ! !WsGraphMorph methodsFor: 'accessing' stamp: 'yo 7/14/2008 22:54'! relativeScale: aBoolean relativeScale _ aBoolean! ! !WsGraphMorph methodsFor: 'accessing' stamp: 'yo 7/15/2008 15:20'! resetTo: aPoint super image: (Form extent: aPoint depth: 16). image fillColor: self color. ! ! !WsGraphMorph methodsFor: 'accessing' stamp: 'yo 7/16/2008 10:35'! setMaxVal: aNumber self maxVal: aNumber. ! ! !WsGraphMorph methodsFor: 'accessing' stamp: 'yo 7/16/2008 10:36'! setMinVal: aNumber self minVal: aNumber. ! ! !WsGraphMorph methodsFor: 'accessing' stamp: 'yo 7/12/2008 13:59'! startIndex ^ startIndex ! ! !WsGraphMorph methodsFor: 'accessing' stamp: 'yo 7/16/2008 10:39'! startIndex: aNumber startIndex ~= aNumber ifTrue: [ startIndex _ aNumber asInteger. self flushCachedForm]. ! ! !WsGraphMorph methodsFor: 'accessing' stamp: 'yo 7/12/2008 13:59'! valueAtCursor data isEmpty ifTrue: [^ 0]. ^ data at: ((cursor truncated max: 1) min: data size) ! ! !WsGraphMorph methodsFor: 'accessing' stamp: 'yo 7/12/2008 13:59'! valueAtCursor: aPointOrNumber data isEmpty ifTrue: [^ 0]. data at: ((cursor truncated max: 1) min: data size) put: (self asNumber: aPointOrNumber). self flushCachedForm. ! ! !WsGraphMorph methodsFor: 'accessing' stamp: 'yo 7/15/2008 10:11'! wantsFFTData ^ dataType ~= #signal ! ! !WsGraphMorph methodsFor: 'accessing' stamp: 'yo 7/16/2008 14:56'! wantsRawData ^ true. ! ! !WsGraphMorph methodsFor: 'commands' stamp: 'yo 7/14/2008 23:00'! appendValue: aPointOrNumber | newVal | newVal _ self asNumber: aPointOrNumber. (data isKindOf: OrderedCollection) ifFalse: [data _ data copyWith: newVal] ifTrue: [data addLast: newVal]. relativeScale ifTrue: [ newVal < minVal ifTrue: [minVal _ newVal]. newVal > maxVal ifTrue: [maxVal _ newVal]. ]. self cursor: data size. self flushCachedForm. ! ! !WsGraphMorph methodsFor: 'commands' stamp: 'yo 7/14/2008 23:52'! centerCursor "Scroll so that the cursor is as close as possible to the center of my window." | w | w _ self width - (2 * self borderWidth). self startIndex: ((cursor - (w // 2)) max: 1). ! ! !WsGraphMorph methodsFor: 'commands' stamp: 'yo 7/12/2008 13:59'! clear self startIndex: 1. self cursor: 1. self data: OrderedCollection new. ! ! !WsGraphMorph methodsFor: 'commands' stamp: 'yo 7/12/2008 13:59'! loadSineWave self loadSoundData: SoundBuffer sineTable. ! ! !WsGraphMorph methodsFor: 'commands' stamp: 'yo 7/12/2008 13:59'! loadSoundData: aCollection | scale absV newData | scale _ 0. aCollection do: [:v | (absV _ v abs) > scale ifTrue: [scale _ absV]]. scale _ 100.0 / scale. newData _ OrderedCollection new: aCollection size. 1 to: aCollection size do: [:i | newData addLast: (scale * (aCollection at: i))]. self data: newData. self startIndex: 1. self cursor: 1. ! ! !WsGraphMorph methodsFor: 'commands' stamp: 'yo 7/12/2008 13:59'! loadSound: aSound self loadSoundData: aSound samples. ! ! !WsGraphMorph methodsFor: 'commands' stamp: 'yo 7/12/2008 13:59'! play self playOnce! ! !WsGraphMorph methodsFor: 'commands' stamp: 'yo 7/12/2008 13:59'! playOnce | scale absV scaledData | data isEmpty ifTrue: [^ self]. "nothing to play" scale _ 1. data do: [:v | (absV _ v abs) > scale ifTrue: [scale _ absV]]. scale _ 32767.0 / scale. scaledData _ SoundBuffer newMonoSampleCount: data size. 1 to: data size do: [:i | scaledData at: i put: (scale * (data at: i)) truncated]. SoundService default playSampledSound: scaledData rate: 11025. ! ! !WsGraphMorph methodsFor: 'commands' stamp: 'yo 7/12/2008 13:59'! reverse data _ data reversed. self flushCachedForm. ! ! !WsGraphMorph methodsFor: 'drawing' stamp: 'yo 7/14/2008 23:53'! drawOn: aCanvas | c | imageFormValid ifFalse: [c := image getCanvas. c translateBy: bounds origin negated during: [:tempCanvas | self drawDataOn: tempCanvas]. imageFormValid := true]. super drawOn: aCanvas. self drawCursorOn: aCanvas! ! !WsGraphMorph methodsFor: 'e-toy support' stamp: 'yo 7/12/2008 13:59'! cursor ^ cursor ! ! !WsGraphMorph methodsFor: 'e-toy support' stamp: 'yo 7/16/2008 10:40'! cursor: aNumber | truncP | cursor ~= aNumber ifTrue: [ cursor _ aNumber. truncP _ aNumber truncated. truncP > data size ifTrue: [cursor _ data size]. truncP < 0 ifTrue: [cursor _ 1]. self keepIndexInView: truncP. ]. ! ! !WsGraphMorph methodsFor: 'e-toy support' stamp: 'yo 7/15/2008 01:11'! delete super delete. model ifNotNil: [model removeView: self]. ! ! !WsGraphMorph methodsFor: 'e-toy support' stamp: 'yo 7/16/2008 15:00'! processData: buf self data: buf. self changed. ! ! !WsGraphMorph methodsFor: 'event handling' stamp: 'yo 7/12/2008 13:59'! handlesMouseDown: evt evt shiftPressed ifTrue: [^ super handlesMouseDown: evt] ifFalse: [^ true]. ! ! !WsGraphMorph methodsFor: 'event handling' stamp: 'yo 7/14/2008 23:53'! mouseMove: evt | x w | x _ evt cursorPoint x - (bounds left + self borderWidth). w _ self width - (2 * self borderWidth). self changed. x < 0 ifTrue: [ cursor _ startIndex + (3 * x). cursor _ (cursor max: 1) min: data size. ^ self startIndex: cursor]. x > w ifTrue: [ cursor _ startIndex + w + (3 * (x - w)). cursor _ (cursor max: 1) min: data size. ^ self startIndex: cursor - w]. cursor _ ((startIndex + x) max: 1) min: data size. ! ! !WsGraphMorph methodsFor: 'initialization' stamp: 'yo 7/16/2008 12:48'! initialize "initialize the state of the receiver" super initialize. "" graphType _ #bar. self borderWidth: 0. color _ Color white. dataColor _ Color black. cursor _ 1. "may be fractional" cursorColor _ Color red. cursorColorAtZeroCrossings _ Color red. startIndex _ 1. maxVal _ 32767. minVal _ -32768. relativeScale _ false. self extent: 400 @ 300. ! ! !WsGraphMorph methodsFor: 'layout' stamp: 'yo 7/14/2008 23:49'! layoutChanged super layoutChanged. imageFormValid _ false. ! ! !WsGraphMorph methodsFor: 'stepping and presenter' stamp: 'yo 7/15/2008 14:05'! step "Make a deferred damage rectangle if I've changed. This allows applications to call methods that invalidate my display at high-bandwidth without paying the cost of doing the damage reporting on ever call; they can merely set hasChanged to true." " super step. hasChanged isNil ifTrue: [hasChanged := false]. hasChanged ifTrue: [self changed. hasChanged := false]"! ! !WsGraphMorph methodsFor: 'private' stamp: 'yo 7/15/2008 10:52'! cursorPosition | ptr r | ptr _ (cursor asInteger max: 1) min: data size. r _ self innerBounds. ^ r left + ptr - startIndex. ! ! !WsGraphMorph methodsFor: 'private' stamp: 'yo 7/15/2008 13:45'! drawBarDataOn: aCanvas | yScale baseLine x start end value left top bottom right rightBound borderWidth | borderWidth _ self borderWidth. data isEmpty ifTrue: [^ self]. maxVal = minVal ifTrue: [ yScale _ 1. ] ifFalse: [ yScale _ (bounds height - (2 * borderWidth)) asFloat / (maxVal - minVal)]. baseLine _ bounds bottom - borderWidth + (minVal * yScale) truncated. rightBound _ (bounds right - borderWidth) truncated. x _ (bounds left + borderWidth) truncated. start _ (startIndex asInteger max: 1) min: data size. end _ (start + bounds width) min: data size. start to: end do: [:i | left _ x. right _ x + 1. right > rightBound ifTrue: [^ self]. value _ (data at: i) asFloat. value >= 0.0 ifTrue: [ top _ baseLine - (yScale * value) truncated. bottom _ baseLine. ] ifFalse: [ top _ baseLine. bottom _ baseLine - (yScale * value) truncated]. aCanvas fillRectangle: (left@top corner: right@bottom) color: dataColor. x _ x + 1]. ! ! !WsGraphMorph methodsFor: 'private' stamp: 'yo 7/16/2008 12:44'! drawCursorOn: aCanvas | ptr x r c | ptr _ (cursor asInteger max: 1) min: data size. c _ cursorColor. ((ptr > 1) and: [ptr < data size]) ifTrue: [ (data at: ptr) sign ~= (data at: ptr + 1) sign ifTrue: [c _ cursorColorAtZeroCrossings]]. r _ self innerBounds. x _ r left + ptr - startIndex. ((x >= r left) and: [x < r right]) ifTrue: [ aCanvas fillRectangle: (x@r top corner: x + 1@r bottom) color: c]. ! ! !WsGraphMorph methodsFor: 'private' stamp: 'yo 7/15/2008 15:12'! drawDataOn: aCanvas aCanvas fillColor: self color. graphType = #bar ifTrue: [ ^ self drawBarDataOn: aCanvas]. graphType = #line ifTrue: [ ^ self drawLineDataOn: aCanvas]. self error: 'unknown graph type'. ! ! !WsGraphMorph methodsFor: 'private' stamp: 'yo 7/15/2008 13:45'! drawLineDataOn: aCanvas | yScale baseLine x start end polygon borderWidth | borderWidth _ self borderWidth. data isEmpty ifTrue: [^ self]. maxVal = minVal ifTrue: [ yScale _ 1.0. ] ifFalse: [ yScale _ (bounds height - (2 * borderWidth)) asFloat / (maxVal - minVal)]. baseLine _ ((bounds bottom - borderWidth + (minVal * yScale)) min: (bounds bottom - borderWidth)). x _ (bounds left + borderWidth) truncated - 2. start _ (startIndex asInteger max: 1) min: data size. end _ (start + bounds width) min: data size. polygon _ WriteStream on: (Array new: end - start + 2). polygon nextPut: (x _ x + 1)@baseLine. start to: end do: [:i | polygon nextPut: (x _ x + 1)@((data at: i) * yScale negated + baseLine)]. polygon nextPut: (x@baseLine). polygon _ polygon contents. aCanvas drawPolygon: polygon color: Color transparent borderWidth: 1 borderColor: dataColor. aCanvas fillRectangle: ((bounds left + borderWidth@baseLine) extent: bounds width@1) color: Color black.! ! !WsGraphMorph methodsFor: 'private' stamp: 'yo 7/16/2008 10:40'! flushCachedForm imageFormValid _ false. self changed. ! ! !WsGraphMorph methodsFor: 'private' stamp: 'yo 7/14/2008 23:51'! keepIndexInView: index | w newStart | w _ bounds width - (2 * self borderWidth). index < startIndex ifTrue: [ newStart _ index - w + 1. ^ self startIndex: (newStart max: 1)]. index > (startIndex + w) ifTrue: [ ^ self startIndex: (index min: data size)]. ! ! !WsGraphMorph methodsFor: '*sound' stamp: 'yo 7/15/2008 01:00'! addCustomMenuItems: aCustomMenu hand: aHandMorph super addCustomMenuItems: aCustomMenu hand: aHandMorph. ! ! !WsGraphMorph methodsFor: '*sound' stamp: 'yo 7/12/2008 13:59'! readDataFromFile | fileName | fileName _ FillInTheBlank request: 'File name?' translated initialAnswer: ''. fileName isEmpty ifTrue: [^ self]. (StandardFileStream isAFileNamed: fileName) ifFalse: [ ^ self inform: 'Sorry, I cannot find that file' translated]. self data: (SampledSound fromAIFFfileNamed: fileName) samples. ! ! !WsGraphMorph class methodsFor: 'scripting' stamp: 'yo 7/16/2008 15:30'! additionsToViewerCategories "Answer a list of ( ) pairs that characterize the phrases this kind of morph wishes to add to various Viewer categories." ^ #( (color ( (slot dataColor 'The color hue of the data' Color readWrite Player getDataColor Player setDataColor:) )) (sampling ( (slot cursor 'The current cursor location, wrapped back to the beginning if appropriate' Number readWrite Player getCursor Player setCursorWrapped:) (slot sampleAtCursor 'The sample value at the current cursor location' Number readWrite Player getSampleAtCursor Player setSampleAtCursor:) (slot lastValue 'The last value obtained' Number readWrite Player getLastValue Player setLastValue:) (command clear 'Clear the graph of current contents') (slot relativeScale 'Whether the display scale is relative to the actual maximum and minimum values in data' Boolean readWrite Player getRelativeScale Player setRelativeScale:) (slot maxVal 'The maximum of the range drawn in the graph' Number readWrite Player getMaxVal Player setMaxVal:) (slot maxVal 'The minimum of the range drawn in the graph' Number readWrite Player getMinVal Player setMinVal:)))) ! ! !WsSignalGraphMorph methodsFor: 'all' stamp: 'yo 7/15/2008 14:27'! appendValue: aPointOrNumber | newVal | newVal _ self asNumber: aPointOrNumber. (data isKindOf: OrderedCollection) ifFalse: [data _ data copyWith: newVal] ifTrue: [data addLast: newVal]. relativeScale ifTrue: [ newVal < minVal ifTrue: [minVal _ newVal]. newVal > maxVal ifTrue: [maxVal _ newVal]. ]. data size > capacity ifTrue: [ self data: (data copyFrom: data size - (capacity // 2) + 1 to: data size). self changed. ]. ! ! !WsSignalGraphMorph methodsFor: 'all' stamp: 'yo 7/15/2008 11:19'! capacity: aNumber capacity _ aNumber. ! ! !WsSignalGraphMorph methodsFor: 'all' stamp: 'yo 7/15/2008 13:33'! handlesMouseUp: evt evt shiftPressed ifTrue: [^ super handlesMouseUp: evt] ifFalse: [^ true]. ! ! !WsSignalGraphMorph methodsFor: 'all' stamp: 'yo 7/15/2008 13:31'! initialize super initialize. graphType _ #line. self capacity: 20000. mouseDown _ false. ! ! !WsSignalGraphMorph methodsFor: 'all' stamp: 'yo 7/15/2008 13:32'! mouseMove: evt super mouseMove: evt. mouseDown _ true. ! ! !WsSignalGraphMorph methodsFor: 'all' stamp: 'yo 7/16/2008 10:39'! mouseUp: evt super mouseUp: evt. mouseDown _ false. self flushCachedForm. self cursor: data size. ! ! !WsSignalGraphMorph methodsFor: 'all' stamp: 'yo 7/16/2008 15:00'! processData: d | oldCursorPosition borderWidth yScale baseLine oldY newY c lastPos | self appendValue: d. mouseDown ifFalse: [self cursor: data size]. oldCursorPosition _ data size - 1 - startIndex. borderWidth _ self borderWidth. maxVal = minVal ifTrue: [ yScale _ 1.0. ] ifFalse: [ yScale _ (bounds height - (2 * borderWidth)) asFloat / (maxVal - minVal)]. baseLine _ ((bounds height - borderWidth + (minVal * yScale)) min: (bounds height - borderWidth)). oldY _ (data at: data size - 1) * yScale negated + baseLine. newY _ (data at: data size) * yScale negated + baseLine. lastPos _ oldCursorPosition@oldY. c _ image getCanvas asBalloonCanvas. c line: lastPos to: (oldCursorPosition+1@newY) width: 1 color: dataColor. lastPos _ lastPos + self position. self invalidRect: (lastPos x@bounds top corner: lastPos x + 2@bounds bottom). ! ! !WsSignalGraphMorph methodsFor: 'all' stamp: 'yo 7/15/2008 09:59'! wantsFFTData ^ false ! ! !WsSignalGraphMorph methodsFor: 'all' stamp: 'yo 7/16/2008 16:24'! wantsRawData ^ false ! ! !WsSonogram methodsFor: 'accessing' stamp: 'yo 7/16/2008 15:09'! color ^ color ! ! !WsSonogram methodsFor: 'accessing' stamp: 'yo 7/16/2008 15:12'! color: aColor color _ aColor. self setUpColorMap! ! !WsSonogram methodsFor: 'accessing' stamp: 'yo 7/16/2008 15:10'! dataColor ^ dataColor ! ! !WsSonogram methodsFor: 'accessing' stamp: 'yo 7/16/2008 15:12'! dataColor: aColor dataColor _ aColor. self setUpColorMap ! ! !WsSonogram methodsFor: 'accessing' stamp: 'yo 7/14/2008 19:50'! model: anObject model _ anObject. ! ! !WsSonogram methodsFor: 'accessing' stamp: 'yo 7/16/2008 15:26'! scrollDelta ^ scrollDelta ! ! !WsSonogram methodsFor: 'accessing' stamp: 'yo 7/16/2008 15:28'! scrollDelta: aNumber scrollDelta _ aNumber min: self width max: 0. ! ! !WsSonogram methodsFor: 'processing' stamp: 'yo 7/16/2008 15:00'! processData: dataArray | normVal r pred quad warp source | normVal := KedamaFloatArray new: dataArray size. normVal replaceFrom: 1 to: dataArray size with: dataArray startingAt: 1. normVal := normVal collect: [:v | v sqrt]. "square root compresses dynamic range" normVal /= 400.0. pred := PredicatedArray predicates: (normVal eToysLT: 0.0) values: normVal type: #Number. pred atAllPut: 0.0. pred predicates: (normVal eToysGT: 1.0). pred atAllPut: 1.0. normVal *= 255.0. (allOne isNil or: [allOne size ~= normVal size or: [words size ~= normVal size]]) ifTrue: [ words := Bitmap new: normVal size. allOne := ByteArray new: words size withAll: 1 ]. pred := PredicatedArray predicates: allOne values: words. pred type: #Number. pred replaceFrom: 1 to: words size with: normVal startingAt: 1. source := Form extent: 4@words size depth: 8 bits: words. (lastX := lastX + 1) > (image width - 1) ifTrue: [self scroll]. quad := Array with: 3@image height with: 3@0 with: 2@0 with: 2@image height. warp := WarpBlt toForm: image. warp combinationRule: Form over; sourceForm: source; sourceQuad: quad destRect: (r := lastX @ 0 extent: 1 @ image height); colorMap: pixValMap; warpBits. self invalidRect: (r translateBy: self position) ! ! !WsSonogram methodsFor: 'processing' stamp: 'yo 7/14/2008 17:58'! wantsFFTData ^ true. ! ! !WsSonogram methodsFor: 'others' stamp: 'yo 7/14/2008 19:50'! delete super delete. model ifNotNil: [model removeView: self]. ! ! !WsSonogram methodsFor: 'others' stamp: 'yo 7/16/2008 15:26'! extent: newExtent | zeros | super image: (Form extent: newExtent depth: 16). allOne := ByteArray new: newExtent y withAll: 1. words := Bitmap new: newExtent y. lastX := -1. zeros _ KedamaFloatArray new: self height withAll: 0. self width timesRepeat: [self processData: zeros]. ! ! !WsSonogram methodsFor: 'others' stamp: 'yo 7/16/2008 15:27'! initialize super initialize. color _ Color white. dataColor _ Color black. self setUpColorMap. ! ! !WsSonogram methodsFor: 'others' stamp: 'yo 7/11/2008 19:24'! scroll image copy: (scrollDelta@0 extent: (image width-scrollDelta)@image height) from: image to: 0@0 rule: Form over. lastX := lastX - scrollDelta. self changed! ! !WsSonogram methodsFor: 'others' stamp: 'yo 7/16/2008 15:11'! setUpColorMap pixValMap _ ((1 to: 256) collect: [:i | (color mixed: (256-i)/255.0 with: dataColor) pixelValueForDepth: 16]) as: Bitmap. ! ! !WsSonogram class methodsFor: 'as yet unclassified' stamp: 'yo 7/16/2008 15:34'! additionsToViewerCategories "Answer a list of ( ) pairs that characterize the phrases this kind of morph wishes to add to various Viewer categories." ^ #( (color ( (slot dataColor 'The color hue of the data' Color readWrite Player getDataColor Player setDataColor:) )) (sampling ( (slot scrollDelta 'The horizontal scrolling stride when data is going off the edget.' Number readWrite Player getScrollDelta Player setScrollDelta:))))! ! !WsWorldStethoscope methodsFor: 'accessing' stamp: 'yo 7/11/2008 16:38'! addView: aMorph self removeView: aMorph. views := views copyWith: aMorph. ! ! !WsWorldStethoscope methodsFor: 'accessing' stamp: 'yo 7/16/2008 11:38'! biasInput ^ biasInput! ! !WsWorldStethoscope methodsFor: 'accessing' stamp: 'yo 7/16/2008 13:28'! biasInput: aBoolean self directInputMode: directInputMode withBiasInput: aBoolean ! ! !WsWorldStethoscope methodsFor: 'accessing' stamp: 'yo 7/15/2008 15:25'! directInputMode ^ directInputMode ! ! !WsWorldStethoscope methodsFor: 'accessing' stamp: 'yo 7/16/2008 13:28'! directInputMode: aBoolean self directInputMode: aBoolean withBiasInput: biasInput ! ! !WsWorldStethoscope methodsFor: 'accessing' stamp: 'yo 7/16/2008 14:37'! directInputMode: aBoolean withBiasInput: bias self configureDirectInputMode: aBoolean bias: bias. ! ! !WsWorldStethoscope methodsFor: 'accessing' stamp: 'yo 7/16/2008 15:05'! directModeReadOut ^ representativeData ! ! !WsWorldStethoscope methodsFor: 'accessing' stamp: 'yo 7/11/2008 16:37'! removeView: aMorph views := views copyWithout: aMorph! ! !WsWorldStethoscope methodsFor: 'accessing' stamp: 'yo 7/15/2008 15:22'! updateInterval ^ updateIntervalInSec ! ! !WsWorldStethoscope methodsFor: 'accessing' stamp: 'yo 7/14/2008 17:49'! updateInterval: aNumber "aNumber in seconds." updateIntervalInSec _ aNumber. self reset. ! ! !WsWorldStethoscope methodsFor: 'accessing' stamp: 'yo 7/14/2008 18:07'! wantsToRecord: aBoolean wantsToRecord _ aBoolean. ! ! !WsWorldStethoscope methodsFor: 'control' stamp: 'yo 7/16/2008 11:41'! start soundInput bufferSize: fft n. soundInput startRecording. self directInputMode: directInputMode withBiasInput: biasInput. listening _ true! ! !WsWorldStethoscope methodsFor: 'control' stamp: 'yo 7/16/2008 11:41'! stop soundInput stopRecording. self directInputMode: directInputMode withBiasInput: biasInput. listening _ false! ! !WsWorldStethoscope methodsFor: 'initialization' stamp: 'yo 7/23/2008 14:16'! initialize super initialize. views := Array new: 0. fft _ FFT new: 512. self cutOffLevel: self defaultCutOffLevel. self offset: self defaultOffset. self passOver: self defaultPassOver. self passUnder: self defaultPassUnder. self directInputMode: false withBiasInput: true. representativeData _ 0. sounds _ Array with: WsSound new with: WsSound new with: WsSound new. soundInput _ SoundInputStream new samplingRate: 22050. self sortByLevel. totalSamplesInGiga _ 0. totalSamples _ 0. recordedCount _ 0. updateIntervalInSec _ 0.25. "in seconds." wantsToRecord _ false. self calcNext: updateIntervalInSec and: soundInput samplingRate. self addView: self. self rangeFinderModeOff! ! !WsWorldStethoscope methodsFor: 'processing' stamp: 'yo 7/14/2008 19:27'! processBuffer | bufCount buffer | soundInput bufferCount = 0 ifTrue: [^ self]. bufCount _ 0. [soundInput bufferCount > 0] whileTrue: [ buffer _ soundInput nextBufferOrNil. bufCount := bufCount + buffer size. ]. self processBuffer: buffer at: bufCount. ! ! !WsWorldStethoscope methodsFor: 'processing' stamp: 'yo 7/28/2008 13:08'! processBuffer: rawArray at: samplesCount | dataArray remSamples newTotalSamplesInGiga newTotalSamples | newTotalSamplesInGiga := totalSamplesInGiga + ((remSamples := samplesCount + totalSamples) // 1000000000). newTotalSamples := remSamples \\ 1000000000. wantsToRecord := wantsToRecord or: [self timePastTotalInGiga: newTotalSamplesInGiga and: newTotalSamples]. totalSamplesInGiga := newTotalSamplesInGiga. totalSamples := newTotalSamples. wantsToRecord ifTrue: [ dataArray := nil. representativeData := rawArray first. views do: [:v | v wantsFFTData ifTrue: [ dataArray ifNil: [dataArray := fft transformDataFrom: rawArray startingAt: 1]. v processData: dataArray ] ifFalse: [ v wantsRawData ifTrue: [v processData: rawArray] ifFalse: [v processData: representativeData]]]. wantsToRecord := false. ]. ! ! !WsWorldStethoscope methodsFor: 'processing' stamp: 'yo 7/16/2008 16:19'! processData: analyzedData | factor deltas pred indices i1 v1 i2 v2 i3 v3 v | analyzedData isCollection ifFalse: [^ self]. self isRangeFinderMode ifTrue: [#(1 2 3 4 5 6 22 23 24 25 45 46 47 68 69 70 90 91 92 113 114 115 135 136 137 159 ) do: [:index | analyzedData at: index put: 0]]. (passMask isNil or: [passMask size ~= (analyzedData size - 1)]) ifTrue: [self resetPassMaskFor: analyzedData]. factor := soundInput samplingRate / fft n. deltas := analyzedData copyFrom: 2 to: analyzedData size. deltas -= analyzedData. pred := PredicatedArray predicates: passMask values: deltas type: #Number. pred atAllPut: 0.0. indices _ Array with: 1 with: 2 with: 3. indices sort: [:a :b | (deltas at: a) < (deltas at: b)]. i1 _ indices at: 1. v1 _ deltas at: i1. i2 _ indices at: 2. v2 _ deltas at: i2. i3 _ indices at: 3. v3 _ deltas at: i3. 4 to: deltas size do: [:index | v _ deltas at: index. v < v1 ifTrue: [i3 _ i2. v3 _ v2. i2 _ i1. v2 _ v1. i1 _ index. v1 _ v] ifFalse: [v < v2 ifTrue: [i3 _ i2. v3 _ v2. i2 _ index. v2 _ v] ifFalse: [v < v3 ifTrue: [i3 _ index. v3 _ v]]]. ]. indices at: 1 put: i1; at: 2 put: i2; at: 3 put: i3. 1 to: 3 do: [:index | | n level frequency | n := (indices at: index) - 1 max: 1. level := analyzedData at: n. frequency := level < self cutOffLevel ifTrue: [frequency := 0. level := 0] ifFalse: [frequency := (n * factor) truncated]. self isRangeFinderMode ifTrue: [frequency isZero ifFalse: [(sounds at: index) frequency: frequency + self offset level: level]] ifFalse: [(sounds at: index) frequency: frequency + self offset level: level]]. sounds := self isSortByLevel ifTrue: [(sounds sort: [:a :b | a level > b level])] ifFalse: [(sounds sort: [:a :b | a frequency > b frequency])]! ! !WsWorldStethoscope methodsFor: 'processing' stamp: 'yo 7/14/2008 16:21'! resetPassMaskFor: data | factor passUnderValue passOverValue | factor := soundInput samplingRate / fft n. passUnderValue := self passUnder - self offset / factor. passOverValue := self passOver - self offset / factor. passMask _ ByteArray new: data size - 1. passMask from: 1 to: passOverValue truncated put: 1. passMask from: passUnderValue truncated + 1 to: passMask size put: 1. ! ! !WsWorldStethoscope methodsFor: 'sort setting' stamp: 'yo 7/20/2008 12:07'! configureDirectInputMode: aBoolean bias: bias soundInput ifNotNil: [ soundInput primSetDevice: 2 name: 'DC Mode Enable'. soundInput primSetSwitch: 2 captureFlag: false parameter: aBoolean. directInputMode _ soundInput primGetSwitch: 2 captureFlag: false channel: 0. directInputMode isInteger ifTrue: [directInputMode _ false]. soundInput primSetDevice: 2 name: 'V_REFOUT Enable'. soundInput primSetSwitch: 2 captureFlag: false parameter: bias. biasInput _ soundInput primGetSwitch: 2 captureFlag: false channel: 0. biasInput isInteger ifTrue: [biasInput _ false]. soundInput primSetDevice: 2 name: nil. ]. ! ! !WsWorldStethoscope methodsFor: 'testing' stamp: 'yo 7/16/2008 13:27'! wantsFFTData ^ directInputMode not. ! ! !WsWorldStethoscope methodsFor: 'testing' stamp: 'yo 7/16/2008 14:56'! wantsRawData ^ directInputMode not. ! ! !WsWorldStethoscope methodsFor: 'private - updating' stamp: 'yo 7/14/2008 18:21'! calcNext: inSec and: rate | next | recordedCount := recordedCount + 1. next := (recordedCount * rate * inSec) truncated. nextUpdateInGiga := next // 1000000000. nextUpdate := next \\ 1000000000. ! ! !WsWorldStethoscope methodsFor: 'private - updating' stamp: 'yo 7/14/2008 17:49'! reset totalSamplesInGiga _ 0. totalSamples _ 0. recordedCount _ 0. wantsToRecord _ false. self calcNext: updateIntervalInSec and: soundInput samplingRate ! ! !WsWorldStethoscope methodsFor: 'private - updating' stamp: 'yo 7/14/2008 18:21'! timePastTotalInGiga: newTotalSamplesInGiga and: newTotalSamples | past | past := newTotalSamplesInGiga > nextUpdateInGiga or: [newTotalSamples > nextUpdate]. past ifTrue: [ self calcNext: updateIntervalInSec and: soundInput samplingRate]. ^ past. ! ! !WsWorldStethoscopeMorph methodsFor: 'accessing' stamp: 'yo 7/20/2008 13:40'! defaultFloatPrecisionFor: aGetSelector (#(#getUpdateInterval ) includes: aGetSelector) ifTrue: [^ 0.01]. ^ super defaultFloatPrecisionFor: aGetSelector. ! ! !WsWorldStethoscopeMorph methodsFor: 'accessing' stamp: 'yo 7/16/2008 14:44'! directModeReadOut ^ model directModeReadOut! ! !WsWorldStethoscopeMorph methodsFor: 'accessing' stamp: 'yo 7/20/2008 13:34'! updateInterval ^ model updateInterval ! ! !WsWorldStethoscopeMorph methodsFor: 'accessing' stamp: 'yo 7/20/2008 13:36'! updateInterval: aNumber model updateInterval: aNumber! ! !WsWorldStethoscopeMorph methodsFor: 'initialization' stamp: 'yo 7/16/2008 14:06'! addControlsIn: aPoint | row | row _ AlignmentMorph newRow color: color; layoutInset: 0; "wrapCentering: #center;" listDirection: #topToBottom; hResizing: #shrinkWrap; vResizing: #shrinkWrap; height: aPoint y + 2. row name: #adjustments. row addMorphBack: (self buildSliderFor: #cutOffLevel min: model cutOffLevelMinValue max: model cutOffLevelMaxValue label: 'cut off level' translated in: aPoint). row addMorphBack: (self buildSliderFor: #offset min: model offsetMinValue max: model offsetMaxValue label: 'calibration ' translated in: aPoint). self addMorphBack: row. row hide. ! ! !WsWorldStethoscopeMorph methodsFor: 'initialization' stamp: 'yo 7/11/2008 16:39'! delete model ifNotNil: [model removeView: self]. super delete. ! ! !WsWorldStethoscopeMorph methodsFor: 'initialization' stamp: 'yo 7/11/2008 18:58'! graphExtent ^ 400@300. ! ! !WsWorldStethoscopeMorph methodsFor: 'initialization' stamp: 'yo 7/20/2008 13:29'! initialize | full | super initialize. model _ WsWorldStethoscope default. model initialize. self hResizing: #shrinkWrap; vResizing: #shrinkWrap. borderWidth := 2. self listDirection: #topToBottom. full _ self addButtonRow. submorphs last addMorphBack: (self inputModeButtonRow). submorphs last addMorphBack: (self makeStatusLightIn: full extent). self addControlsIn: full extent. biasModeLight color: (model biasInput ifTrue: [Color yellow] ifFalse: [Color lightGray]). ! ! !WsWorldStethoscopeMorph methodsFor: 'initialization' stamp: 'yo 7/17/2008 20:41'! inputModeButtonRow | row | row _ AlignmentMorph newRow vResizing: #shrinkWrap. row addMorphBack: (Morph new extent: 10 @ 1; color: Color transparent). row addMorphBack: (directModeLight _ self buttonName: 'AC ' translated action: #toggleDirectMode). row addMorphBack: (Morph new extent: 4 @ 1; color: Color transparent). row addMorphBack: (biasModeLight _ self buttonName: 'Bias' translated action: #toggleBias). row addMorphBack: (Morph new extent: 4 @ 1; color: Color transparent). ^ row ! ! !WsWorldStethoscopeMorph methodsFor: 'menu and buttons' stamp: 'yo 7/15/2008 10:09'! invokeMenu | aMenu graphMenu | aMenu _ MenuMorph new. aMenu add: 'set sampling rate' translated target: self action: #setSamplingRate. aMenu add: 'set FFT size' translated target: self action: #setFFTSize. aMenu add: self adjustmentsString target: self action: #toggleAdjustments. graphMenu _ MenuMorph new. graphMenu add: 'sonogram' translated target: self action: #addSonogram. graphMenu add: 'signal' translated target: self action: #addSignalGraph. graphMenu add: 'spectrum' translated target: self action: #addSpectrumGraph. graphMenu add: 'data' translated target: self action: #addDataGraph. aMenu add: 'add a graph...' translated subMenu: graphMenu. aMenu invokeModal.! ! !WsWorldStethoscopeMorph methodsFor: 'menu and buttons' stamp: 'yo 7/11/2008 16:09'! offsetDecrease | newValue slider | model offsetDecrease. newValue := model offset. slider := self submorphNamed: #offset. slider value: newValue + model offsetMinValue negated / (model offsetMaxValue - model offsetMinValue)! ! !WsWorldStethoscopeMorph methodsFor: 'menu and buttons' stamp: 'yo 7/11/2008 16:10'! offsetIncrease | newValue slider | model offsetIncrease. newValue _ model offset. slider _ self submorphNamed: #offset. slider value: newValue + model offsetMinValue negated / (model offsetMaxValue - model offsetMinValue)! ! !WsWorldStethoscopeMorph methodsFor: 'menu and buttons' stamp: 'yo 7/11/2008 16:16'! setFFTSize ^ model setFFTSize ! ! !WsWorldStethoscopeMorph methodsFor: 'menu and buttons' stamp: 'yo 7/11/2008 16:16'! setSamplingRate ^ model setSamplingRate ! ! !WsWorldStethoscopeMorph methodsFor: 'menu and buttons' stamp: 'yo 7/16/2008 14:33'! toggleBias model biasInput: model biasInput not. biasModeLight color: (model biasInput ifTrue: [Color yellow] ifFalse: [Color lightGray]). ! ! !WsWorldStethoscopeMorph methodsFor: 'menu and buttons' stamp: 'yo 7/16/2008 14:36'! toggleDirectMode model directInputMode: model directInputMode not. directModeLight label: (model directInputMode ifTrue: ['DC' translated] ifFalse: ['AC' translated]) font: Preferences standardButtonFont.! ! !WsWorldStethoscopeMorph methodsFor: 'menus' stamp: 'yo 7/23/2008 14:39'! addDataGraph | graph | graph := WsSignalGraphMorph new extent: self graphExtent. graph setNameTo: 'Data' translated. graph dataType: #signal. graph data: (OrderedCollection with: 0). graph model: model. model addView: graph. graph openInHand. ! ! !WsWorldStethoscopeMorph methodsFor: 'menus' stamp: 'yo 7/23/2008 14:39'! addSignalGraph | graph | graph := WsGraphMorph new extent: self graphExtent. graph setNameTo: 'Signal' translated. graph dataType: #signal. graph data: (Array with: 0 with: 0 with: 0 with: 0). graph model: model. model addView: graph. graph openInHand. ! ! !WsWorldStethoscopeMorph methodsFor: 'menus' stamp: 'yo 7/23/2008 14:37'! addSonogram | graph | graph := WsSonogram new extent: self graphExtent. graph setNameTo: 'Sonogram' translated. graph scrollDelta: self graphExtent x. graph model: model. model addView: graph. graph openInHand. ! ! !WsWorldStethoscopeMorph methodsFor: 'menus' stamp: 'yo 7/23/2008 14:40'! addSpectrumGraph | graph | graph := WsGraphMorph new extent: self graphExtent. graph setNameTo: 'Spectrum' translated. graph dataType: #spectrum. graph minVal: 0. graph data: (FloatArray new: 0). graph maxVal: 500000. graph model: model. model addView: graph. graph openInHand. ! ! !WsWorldStethoscopeMorph methodsFor: 'menus' stamp: 'yo 7/16/2008 14:41'! rangeFinderModeString | label | label _ 'range finder mode' translated. ^ model isRangeFinderMode ifTrue: ['' , label] ifFalse: ['' , label]! ! !WsWorldStethoscopeMorph methodsFor: 'menus' stamp: 'yo 7/16/2008 14:41'! sortByFrequencyString | label | label _ 'sort by frequency' translated. ^ model isSortByFrequency ifTrue: ['' , label] ifFalse: ['' , label]! ! !WsWorldStethoscopeMorph methodsFor: 'menus' stamp: 'yo 7/16/2008 14:41'! sortByLevelString | label | label _ 'sort by level' translated. ^ model isSortByLevel ifTrue: ['' , label] ifFalse: ['' , label]! ! !WsWorldStethoscopeMorph methodsFor: 'stepping' stamp: 'yo 7/14/2008 16:48'! step model isListening ifTrue: [statusLight color: Color yellow] ifFalse: [statusLight color: Color gray]. model processBuffer! ! !WsWorldStethoscopeMorph methodsFor: 'stepping' stamp: 'yo 7/14/2008 16:49'! stepTime ^ 0. ! ! !WsWorldStethoscopeMorph methodsFor: 'private' stamp: 'yo 7/11/2008 16:12'! buildSliderFor: aspectSymbol min: minNumber max: maxNumber label: labelString in: aPoint | slider row | slider _ SimpleSliderMorph new color: Color gray; extent: (aPoint x * 0.75) asInteger@(aPoint y*0.6) asInteger; target: self; actionSelector: (aspectSymbol , ':') asSymbol; minVal: minNumber; maxVal: maxNumber; adjustToValue: (model perform: aspectSymbol); name: aspectSymbol. row _ AlignmentMorph newRow color: color; layoutInset: 0; wrapCentering: #center; hResizing: #spaceFill; vResizing: #rigid; height: aPoint y + 2. row addMorphBack: (StringMorph contents: labelString font: Preferences standardEToysFont). row addMorphBack: (Morph new extent: 4 @ 1; color: Color transparent). row addMorphBack: (self buttonName: '-' action: aspectSymbol , 'Decrease'). row addMorphBack: (Morph new extent: 4 @ 1; color: Color transparent). row addMorphBack: slider. row addMorphBack: (Morph new extent: 4 @ 1; color: Color transparent). row addMorphBack: (self buttonName: '+' action: aspectSymbol , 'Increase'). ^row! ! !WsWorldStethoscopeMorph class methodsFor: 'scripting' stamp: 'yo 7/16/2008 14:44'! additionsToViewerCategories ^ # ((sound ( (slot readOut 'the value for the direct input mode.' Number readOnly player getDirectModeReadOut unused unused) (slot frequency1 'frequency-1 of sound' Number readOnly player getFrequency1 unused unused) (slot level1 'level-1 of sound' Number readOnly player getLevel1 unused unused) (slot frequency2 'frequency-2 of sound' Number readOnly player getFrequency2 unused unused) (slot level2 'level-2 of sound' Number readOnly player getLevel2 unused unused) (slot frequency3 'frequency-3 of sound' Number readOnly player getFrequency3 unused unused) (slot level3 'level-3 of sound' Number readOnly player getLevel3 unused unused) (slot dialNumber 'dial number of sound' String readOnly player getDialNumber unused unused) (slot soundListening 'whether the stethoscope is listening' Boolean readWrite Player getListening Player setListening:) (slot passOver 'high pass filter value' Number readWrite player getPassOver player setPassOver:) (slot passUnder 'low pass filter value' Number readWrite player getPassUnder player setPassUnder:) (slot cutOffLevel 'cut off level' Number readWrite player getCutOffLevel player setCutOffLevel:) (slot updateInterval: 'specify how often read the input.' Number readWrite player getUpdateInterval player setUpdateInterval:) ))) ! ! WsWorldStethoscopeMorph removeSelector: #addGraphIn:! WsWorldStethoscopeMorph removeSelector: #addSliderFor:min:max:label:! WsWorldStethoscopeMorph removeSelector: #addSliders! WsWorldStethoscopeMorph removeSelector: #addSlidersIn:! WsWorldStethoscopeMorph removeSelector: #addSonoGraph! WsWorldStethoscopeMorph removeSelector: #buildSliderFor:min:max:label:! WsWorldStethoscopeMorph removeSelector: #doesNotUnderstand:! WsWorldStethoscopeMorph removeSelector: #graphString! WsWorldStethoscopeMorph removeSelector: #isRunning! WsWorldStethoscopeMorph removeSelector: #makeStatusLight! WsWorldStethoscopeMorph removeSelector: #setDisplayType! WsWorldStethoscopeMorph removeSelector: #toggleGraph! AlignmentMorph subclass: #WsWorldStethoscopeMorph instanceVariableNames: 'statusLight model directModeLight biasModeLight' classVariableNames: '' poolDictionaries: '' category: 'WS-Sound-Interface'! !WsWorldStethoscopeMorph reorganize! ('accessing' cutOffLevel cutOffLevel: defaultFloatPrecisionFor: directModeReadOut frequency1 frequency2 frequency3 level1 level2 level3 passOver passOver: passUnder passUnder: updateInterval updateInterval:) ('initialization' addButtonRow addControlsIn: delete graphExtent initialize inputModeButtonRow) ('menu and buttons' cutOffLevelDecrease cutOffLevelIncrease invokeMenu offsetDecrease offsetIncrease setFFTSize setSamplingRate start stop toggleAdjustments toggleBias toggleDirectMode) ('menus' addCustomMenuItems:hand: addDataGraph addSignalGraph addSonogram addSpectrumGraph rangeFinderModeString sortByFrequencyString sortByLevelString) ('phone utilities' dialNumber) ('stepping' step stepTime) ('private' adjustmentsString buildSliderFor:min:max:label:in: buttonName:action: makeStatusLightIn:) ! WsWorldStethoscope removeSelector: #configureDirectInputMode:! WsWorldStethoscope removeSelector: #directInputMode:withBias:! WsWorldStethoscope removeSelector: #processBuffer:! WsWorldStethoscope removeSelector: #processBuffer:fftData:at:! WsWorldStethoscope removeSelector: #updateSounds:! Object subclass: #WsWorldStethoscope instanceVariableNames: 'soundInput fft sounds offset cutOffLevel sortType listening passOver passUnder passMask rangeFinderMode directInputMode representativeData biasInput totalSamplesInGiga totalSamples recordedCount wantsToRecord nextUpdateInGiga nextUpdate updateIntervalInSec views' classVariableNames: '' poolDictionaries: '' category: 'WS-Sound-Interface'! !WsWorldStethoscope reorganize! ('accessing' addView: biasInput biasInput: cutOffLevel cutOffLevel: directInputMode directInputMode: directInputMode:withBiasInput: directModeReadOut frequency frequency1 frequency2 frequency3 level level1 level2 level3 offset offset: passOver passOver: passUnder passUnder: rangeFindeMode: rangeFinderModeOff rangeFinderModeOn rangeFinderMode: removeView: toggleRangeFinderMode updateInterval updateInterval: wantsToRecord:) ('constants' cutOffLevelMaxValue cutOffLevelMinValue defaultCutOffLevel defaultOffset defaultPassOver defaultPassUnder offsetMaxValue offsetMinValue) ('control' cutOffLevelDecrease cutOffLevelIncrease offsetDecrease offsetIncrease setFFTSize setSamplingRate start stop) ('fileIn/out' storeDataOn:) ('initialization' initialize) ('phone utilities' dialNumber dialNumbers highFrequencies lowFrequencies permissibleRange) ('processing' processBuffer processBuffer:at: processData: resetPassMaskFor:) ('sort setting' configureDirectInputMode:bias: sortByFrequency sortByLevel) ('testing' isListening isRangeFinderMode isSortByFrequency isSortByLevel wantsFFTData wantsRawData) ('private - updating' calcNext:and: reset timePastTotalInGiga:and:) ! WsSonogram removeSelector: #calcIntervals:and:! WsSonogram removeSelector: #calcNext:and:! WsSonogram removeSelector: #extent:minVal:maxVal:scrollDelta:! WsSonogram removeSelector: #extent:scrollDelta:! WsSonogram removeSelector: #plotColumn:! WsSonogram removeSelector: #processBuffer:! WsSonogram removeSelector: #processBuffer:at:! WsSonogram removeSelector: #processBuffer:at:in:! WsSonogram removeSelector: #reset! WsSonogram removeSelector: #samplingRate:! WsSonogram removeSelector: #setPixMap! WsSonogram removeSelector: #timePastTotalInGiga:and:! WsSonogram removeSelector: #updateInterval:! !WsSonogram reorganize! ('accessing' color color: dataColor dataColor: model: scrollDelta scrollDelta:) ('processing' processData: wantsFFTData) ('others' delete extent: initialize scroll setUpColorMap) ! WsSignalGraphMorph removeSelector: #extent:! WsSignalGraphMorph removeSelector: #keepIndexInView:! WsSignalGraphMorph removeSelector: #processBuffer:! WsSignalGraphMorph removeSelector: #scroll! WsSignalGraphMorph removeSelector: #startIndex:! !WsSignalGraphMorph reorganize! ('all' appendValue: capacity: handlesMouseUp: initialize mouseMove: mouseUp: processData: wantsFFTData wantsRawData) ! WsGraphMorph class removeSelector: #descriptionForPartsBin! !WsGraphMorph class reorganize! ('scripting' additionsToViewerCategories) ! WsGraphMorph removeSelector: #convertToCurrentVersion:refStream:! WsGraphMorph removeSelector: #defaultColor! WsGraphMorph removeSelector: #drawFloatArrayDataOn:! WsGraphMorph removeSelector: #openWaveEditor! WsGraphMorph removeSelector: #processBuffer:! WsGraphMorph removeSelector: #RectangledrawFloatArrayDataOn:! WsGraphMorph removeSelector: #scroll! WsGraphMorph removeSelector: #setMaxVal! WsGraphMorph removeSelector: #sonogramProcessBuffer:! !WsGraphMorph reorganize! ('accessing' color color: cursorAtEnd cursorColor cursorColorAtZeroCrossing cursorColorAtZeroCrossings: cursorColor: cursorWrapped: data dataColor dataColor: dataType: data: extent: graphType: interpolatedValueAtCursor lastValue lastValue: maxVal maxVal: minVal minVal: model: relativeScale relativeScale: resetTo: setMaxVal: setMinVal: startIndex startIndex: valueAtCursor valueAtCursor: wantsFFTData wantsRawData) ('commands' appendValue: centerCursor clear loadSineWave loadSoundData: loadSound: play playOnce reverse) ('drawing' drawOn:) ('e-toy support' cursor cursor: delete processData:) ('event handling' handlesMouseDown: mouseMove:) ('initialization' initialize) ('layout' layoutChanged) ('stepping and presenter' step) ('private' cursorPosition drawBarDataOn: drawCursorOn: drawDataOn: drawLineDataOn: flushCachedForm keepIndexInView:) ('*sound' addCustomMenuItems:hand: readDataFromFile) ! !SoundRecorder reorganize! ('initialization' initialize initializeRecordingState) ('accessing' codec codecSignature codec: desiredSampleRate: isActive isPaused meterLevel recordLevel recordLevel: samplingRate samplingRate:) ('recording controls' clearRecordedSound hasRecordedSound pause playback resumeRecording startRecording stopRecording verifyExistenceOfRecordedSound) ('trimming' copyFrom:to:normalize:dcOffset: copyTo:from:to:from:startingAt:normalize:dcOffset: endPlace firstSampleOverThreshold:dcOffset:startingAt: normalizeFactorFor:min:max:dcOffset: place:plus: scanForEndThreshold:dcOffset:minLull:startingAt: scanForStartThreshold:dcOffset:minDur:startingAt: segmentsAbove:normalizedVolume: suppressSilence trim:normalizedVolume:) ('private' allocateBuffer emitBuffer: emitPartialBuffer meterFrom:count:in: recordLoop samplesPerFrame) ('primitives' primGetActualRecordingSampleRate primGetSwitch:captureFlag:channel: primRecordSamplesInto:startingAt: primSetDevice:name: primSetRecordLevel: primSetSwitch:captureFlag:parameter: primStartRecordingDesiredSampleRate:stereo:semaIndex: primStopRecording) ('results' condensedChannels condensedSamples condensedStereoSound recordedSound soundSegments) ! Player removeSelector: #getReadOut! ByteArray removeSelector: #or:!