'From etoys2.2 of 24 September 2007 [latest update: #1719] on 20 October 2007 at 5:37:09 pm'! "Change Set: anonymousSound-sw Date: 20 October 2007 Author: Scott Wallace, Karl Ramberg Handle a drop of an external sound file by opening an AnonymousSoundMorph, allowing the user to play the sound, drop it into a piano roll or an event roll, and also offering the option to add the sound to the sound library. The AnonymousSoundMorphs obtained from the 'hand me a sound token' menu item in the Sound Recorder's menu are now also of the same expanded sort, which is to say, they show a prospective name for the sound, and provide controls to play, stop, and save. When deployed inside a PianoRoll, AnonymousSoundMorphs slim down to dimensions and proportions appropriate for the Piano Roll. When/if returned to the desktop, they flesh out to their full form with button controls."! AbstractMediaEventMorph subclass: #AnonymousSoundMorph instanceVariableNames: 'sound interimName ' classVariableNames: '' poolDictionaries: '' category: 'Sound-Interface'! !AnonymousSoundMorph commentStamp: 'sw 10/19/2007 16:56' prior: 0! Holds a free-standing sound, i.e. one not associated with the system's sound library. Can be played by hitting Play button, and can stop its playing by hitting Stop. Can be dropped into a piano roll or into an event roll Can also be named and added to the system sound library, by hitting the save button.! !AnonymousSoundMorph methodsFor: 'initialization' stamp: 'sw 10/19/2007 19:13'! addButtonRow "Add the row of control buttons." | row button | row := AlignmentMorph newRow vResizing: #shrinkWrap; color: Color transparent. row addVariableTransparentSpacer. button := SimpleButtonMorph new label: 'Play' translated font: ScriptingSystem fontForEToyButtons; target: self; actionSelector: #playSound. row addMorphBack: button. row addVariableTransparentSpacer. button := SimpleButtonMorph new label: 'Stop' translated font: ScriptingSystem fontForEToyButtons; target: self; actionSelector: #stopSound. row addMorphBack: button. row addVariableTransparentSpacer. button := SimpleButtonMorph new label: 'Save' translated font: ScriptingSystem fontForEToyButtons; target: self; actionSelector: #addToSoundLibrary . row addMorphBack: button. row addVariableTransparentSpacer. self addMorphBack: row! ! !AnonymousSoundMorph methodsFor: 'initialization' stamp: 'sw 10/19/2007 14:50'! initialize "initialize the state of the receiver" super initialize. self height: 18. self balloonTextSelector: #soundMorphHelpString. self on: #doubleClick send: #playSound to: self. self on: #mouseMove send: #openInHand to: self. self on: #click send: #stopSound to: self. interimName := SampledSound unusedSoundNameLike: 'Unnamed' translated! ! !AnonymousSoundMorph methodsFor: 'initialization' stamp: 'sw 10/19/2007 16:57'! sound: aSampledSound interimName: anInterimName "Establish the sound object and an interim name." | aStringMorph | self removeAllMorphs. self hResizing: #shrinkWrap; vResizing: #shrinkWrap. borderWidth _ 2. self listDirection: #topToBottom. sound := aSampledSound. interimName := anInterimName. aStringMorph := StringMorph contents: interimName font: ScriptingSystem fontForEToyButtons. self addMorphBack: aStringMorph. self addButtonRow. self balloonTextSelector: #soundMorphHelpString. self setNameTo: interimName! ! !AnonymousSoundMorph methodsFor: 'piano roll' stamp: 'sw 10/19/2007 16:30'! justDroppedIntoPianoRoll: newOwner event: evt "The receiver was just dropped into a piano roll... respond accordingly." | startX lengthInTicks endX | super justDroppedIntoPianoRoll: newOwner event: evt. submorphs size > 1 ifTrue: [submorphs last delete]. self hResizing: #rigid; clipSubmorphs: true. startTimeInScore _ newOwner timeForX: self left. lengthInTicks _ newOwner scorePlayer ticksForMSecs: sound duration * 1000.0. endTimeInScore _ startTimeInScore + lengthInTicks. endTimeInScore > newOwner scorePlayer durationInTicks ifTrue: [newOwner scorePlayer updateDuration]. startX _ newOwner xForTime: startTimeInScore. endX _ newOwner xForTime: endTimeInScore. self width: endX - startX! ! !AnonymousSoundMorph methodsFor: 'piano roll' stamp: 'sw 10/19/2007 16:31'! justDroppedInto: aMorph event: evt "The receiver was just dropped into some container... respond accordingly." super justDroppedInto: aMorph event: evt. (aMorph isKindOf: PianoRollScoreMorph ) ifTrue: [^ self]. submorphs size < 2 ifTrue: [self sound: sound interimName: interimName]! ! !AnonymousSoundMorph methodsFor: 'menu' stamp: 'sw 10/19/2007 15:10'! addCustomMenuItems: aMenu hand: aHandMorph "Add morph-specific items to the given menu which was invoked by the given hand. This method provides is invoked both from the halo-menu and from the control-menu regimes." super addCustomMenuItems: aMenu hand: aHandMorph. aMenu addTranslatedList: #( - ('wave editor' openWaveEditorOnSound 'open a wave-editor tool with this sound as its iniital sound')) translatedNoop! ! !AnonymousSoundMorph methodsFor: 'menu' stamp: 'sw 10/19/2007 16:34'! addToSoundLibrary "Add the receiver's sound to the library, and hand the user a tile representing it." | aName tile | aName := FillInTheBlank request: 'kindly give the sound a name: ' initialAnswer: (interimName ifNil: ['']). aName isEmptyOrNil ifTrue: [^ self]. aName := SampledSound unusedSoundNameLike: aName. SampledSound addLibrarySoundNamed: aName samples: sound samples samplingRate: sound samplingRate. tile _ SoundTile new literal: aName. tile bounds: tile fullBounds. tile center: self fullBoundsInWorld center. (ScriptingTileHolder around: tile) center: self fullBoundsInWorld center; openInWorld. self delete! ! !AnonymousSoundMorph methodsFor: 'menu' stamp: 'sw 10/19/2007 15:11'! openWaveEditorOnSound "Open a wave-editor tool on the receiver's sound" WaveEditor openOn: sound samples! ! !AnonymousSoundMorph methodsFor: 'menu' stamp: 'sw 10/18/2007 22:15'! stopPlayingSound "If the receiver's sound is playing, stop it." sound pause! ! !AnonymousSoundMorph class methodsFor: 'fileIn/Out' stamp: 'sw 10/19/2007 15:18'! fileReaderServicesForFile: fullName suffix: suffix "Answer the file services associated with given file" ^ (self registeredAudioFileSuffixes includes: suffix) ifTrue: [self services] ifFalse: [#()]! ! !AnonymousSoundMorph class methodsFor: 'fileIn/Out' stamp: 'sw 10/19/2007 19:27'! fromFileName: fullName "Create an instance of the receiver from the given file path." | newPlayer aSound ext aName | newPlayer _ self new initialize. ('*aif' match: fullName) ifTrue: [aSound := SampledSound fromAIFFfileNamed: fullName]. ('*wav' match: fullName) ifTrue: [aSound := SampledSound fromWaveFileNamed: fullName]. newPlayer := self new. ext := FileDirectory extensionFor: fullName. aName := (FileDirectory on: fullName) pathParts last. ext size > 0 ifTrue: [aName := aName copyFrom: 1 to: (aName size - (ext size + 1))]. newPlayer sound: aSound interimName: aName. newPlayer openInWorld! ! !AnonymousSoundMorph class methodsFor: 'file suffixes' stamp: 'sw 10/19/2007 15:17'! registeredAudioFileSuffixes "Answer the file extensions for which the receiver registers audio services with FileList." "AnonymousSoundMorph registeredAudioFileSuffixes" ^ { 'aif'. 'wav'}! ! !RecordingControls methodsFor: 'private' stamp: 'sw 10/20/2007 02:23'! makeSoundMorph "Hand the user an anonymous-sound object representing the receiver's sound." | m aName | recorder verifyExistenceOfRecordedSound ifFalse: [^ self]. recorder pause. recordingSaved := true. m _ AnonymousSoundMorph new. m sound: recorder recordedSound interimName: (aName := 'Unnamed Sound'). m setNameTo: aName. ActiveHand attachMorph: m! ! AnonymousSoundMorph removeSelector: #makeAppearanceReflectSound! AnonymousSoundMorph removeSelector: #sound:! AbstractMediaEventMorph subclass: #AnonymousSoundMorph instanceVariableNames: 'sound interimName' classVariableNames: '' poolDictionaries: '' category: 'Sound-Interface'! "Postscript:" FileList initialize.!