'From Squeak3.5 of ''11 April 2003'' [latest update: #5180] on 25 January 2004 at 2:44:36 pm'!"Change Set: NM-MusicDate: 24 August 2003Author: Norberto ManzanosFramework for music"!Smalltalk renameClassNamed: #AbstractChordPlayer as: #AbstractChordMaker!Object subclass: #AbstractChordMaker instanceVariableNames: 'window chord textNotes textInterval volumeEdit margin ' classVariableNames: '' poolDictionaries: '' category: 'Music-Morphs'!Object subclass: #AbstractMusicalNote instanceVariableNames: 'name pitch ' classVariableNames: 'DoubleFlatedChromatic DoubleSharpedChromatic FlatedChromatic NaturalScale SharpedChromatic ' poolDictionaries: '' category: 'Music-Core'!!AbstractMusicalNote commentStamp: '' prior: 0!A musical note that only deals with abstract tones. MusicalNote is the concret class.It can be translated to a an interval, asked for the intervalic distance between other amnadd sharps or flats, etc.!AbstractChordMaker subclass: #ChordMaker instanceVariableNames: 'chordEdit ' classVariableNames: '' poolDictionaries: '' category: 'Music-Morphs'!!ChordMaker commentStamp: '' prior: 0!ChordPlayer new!AbstractChordMaker subclass: #ChordMaker2 instanceVariableNames: 'scale scaleEdit intervalEdit chordEdit ' classVariableNames: '' poolDictionaries: '' category: 'Music-Morphs'!Smalltalk renameClassNamed: #ChordMorph2 as: #ChordMorph!InterimSoundMorph subclass: #ChordMorph instanceVariableNames: 'name ' classVariableNames: '' poolDictionaries: '' category: 'Music-Morphs'!Smalltalk renameClassNamed: #ChordPalette as: #ChordPaletteMorph!PasteUpMorph subclass: #ChordPaletteMorph instanceVariableNames: 'scales scaleIndex scaleButton chordBar ' classVariableNames: '' poolDictionaries: '' category: 'Music-Morphs'!Smalltalk renameClassNamed: #ChordGame as: #ChordPlayerMorph!PasteUpMorph subclass: #ChordPlayerMorph instanceVariableNames: 'chordArea buttonArea handleDurations ' classVariableNames: '' poolDictionaries: '' category: 'Music-Morphs'!Object subclass: #Measure instanceVariableNames: 'beats division numerator denominator ' classVariableNames: '' poolDictionaries: '' category: 'Music-Core'!Object subclass: #Metronomo instanceVariableNames: 'ticking pulso tickDuration ' classVariableNames: '' poolDictionaries: '' category: 'Music-Old'!Object subclass: #MusicalInterval instanceVariableNames: 'number type steps ' classVariableNames: 'InvertedIntervals NaturalScale ' poolDictionaries: '' category: 'Music-Core'!AbstractMusicalNote subclass: #MusicalNote instanceVariableNames: 'octave duration ' classVariableNames: '' poolDictionaries: '' category: 'Music-Core'!!MusicalNote commentStamp: '' prior: 0!A note with an octave ... and a duration? !Object subclass: #MusicalScale instanceVariableNames: 'notes steps ' classVariableNames: '' poolDictionaries: '' category: 'Music-Core'!Object subclass: #MusicalStream instanceVariableNames: 'notes ' classVariableNames: '' poolDictionaries: '' category: 'Music-Core'!!MusicalStream commentStamp: '' prior: 0!A collection of notes. Chords and Melody are it subclases!MusicalStream subclass: #Chord instanceVariableNames: 'root name intervals duration structure ' classVariableNames: '' poolDictionaries: '' category: 'Music-Core'!MusicalStream subclass: #Melody instanceVariableNames: 'rhythm maps ' classVariableNames: '' poolDictionaries: '' category: 'Music-Core'!!Melody commentStamp: 'nm 6/5/2003 18:52' prior: 0!A musicalStream, where notes are played sequentially, and with a concret rhythmMessages on rhythmic questions (bars, measures, etc) are sended to Rhythm via DNUmaps holds RunArrays for melodic transformation.ex. maps at: #loudness maps loudness.!PasteUpMorph subclass: #PaintMusicMorph instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Music-Morphs'!Object subclass: #PreArmonizer instanceVariableNames: 'tonality melody rules ' classVariableNames: '' poolDictionaries: '' category: 'Music-Core'!Object subclass: #Rhythm instanceVariableNames: 'tempo measure notes bars tempoMap measureMap ' classVariableNames: '' poolDictionaries: '' category: 'Music-Core'!Object subclass: #RhythmC instanceVariableNames: 'tempo notes durations articulationMap tempoMap measureMap ' classVariableNames: '' poolDictionaries: '' category: 'Music-Old'!Object subclass: #Score instanceVariableNames: 'voices ' classVariableNames: '' poolDictionaries: '' category: 'Music-Core'!Object subclass: #Tempo instanceVariableNames: 'value ' classVariableNames: '' poolDictionaries: '' category: 'Music-Core'!Object subclass: #Tonality instanceVariableNames: 'root mode scale ' classVariableNames: '' poolDictionaries: '' category: 'Music-Core'!!Tonality commentStamp: 'nm 12/22/2003 13:33' prior: 0!Knows its root note, its scale, its mode.Can construct tonicChord, tonicChords collection #(I VI III), etc!!AbstractChordMaker methodsFor: 'actions' stamp: 'nm 11/14/2002 12:38'!closeself chord notNil ifTrue:[ self chord close. self showNotes].! !!AbstractChordMaker methodsFor: 'actions' stamp: 'nm 11/14/2002 12:38'!constructChordself chord isNil ifTrue:[ self chordOn: self notes].! !!AbstractChordMaker methodsFor: 'actions' stamp: 'nm 6/3/2003 19:03'!invertself chord notNil ifTrue:[ self chord invert:1. self showNotes].! !!AbstractChordMaker methodsFor: 'actions' stamp: 'nm 11/14/2002 12:38'!octaveDownself chord notNil ifTrue:[ self chord octaveDown. self showNotes].! !!AbstractChordMaker methodsFor: 'actions' stamp: 'nm 11/14/2002 12:38'!octaveUpself chord notNil ifTrue:[ self chord octaveUp. self showNotes].! !!AbstractChordMaker methodsFor: 'actions' stamp: 'nm 11/14/2002 12:38'!openself chord notNil ifTrue:[ self chord open. self showNotes].! !!AbstractChordMaker methodsFor: 'actions' stamp: 'nm 11/14/2002 12:38'!playArpeggioself constructChord.self showNotes.chord arpeggioOn: FMClarinetSound.! !!AbstractChordMaker methodsFor: 'actions' stamp: 'nm 6/3/2003 19:34'!playNotesself constructChord.self showNotes.chord playOn: FMClarinetSound loudness: self volume.! !!AbstractChordMaker methodsFor: 'actions' stamp: 'nm 11/14/2002 12:38'!rootself chord notNil ifTrue:[ self chord fromRoot. self showNotes].! !!AbstractChordMaker methodsFor: 'actions' stamp: 'nm 11/14/2002 12:38'!rotateself chord notNil ifTrue:[ self chord rotate:2. self showNotes].! !!AbstractChordMaker methodsFor: 'actions' stamp: 'nm 1/20/2004 16:57'!sendChordself constructChord.self showNotes.(ChordMorph name:self chord name) sound: chord; openInHand.! !!AbstractChordMaker methodsFor: 'actions' stamp: 'nm 11/18/2002 15:42'!showNotestextNotes contents: self chord printNotes! !!AbstractChordMaker methodsFor: 'actions' stamp: 'nm 6/3/2003 19:04'!transposeself chord notNil ifTrue:[ self chord transposeTo: self interval. self showNotes. self chordEdit contents: chord name].! !!AbstractChordMaker methodsFor: 'actions' stamp: 'nm 1/20/2004 17:12'!volume^volumeEdit isNil ifTrue:[200] ifFalse:[volumeEdit value * 300]! !!AbstractChordMaker methodsFor: 'initialization' stamp: 'nm 1/21/2004 12:16'!initialize"los anulados tienen problemas. Los saco para el essay"self initializeWindow.margin_ 30.window addMorph: (self initializePlayButton); addMorph: (self initializeArpeggioButton); addMorph: (self initializeUpButton); addMorph: (self initializeDownButton); addMorph: (self initializeOpenButton); addMorph: (self initializeCloseButton); addMorph: (self initializeInvertButton); addMorph: (self initializeRootButton); addMorph: (self initializeRotateButton); addMorph: (self initializeTransposeButton); addMorph: (self initializeIntervalText); addMorph: (self initializeVolumeEdit); addMorph: (self initializeText); addMorph: (self initializeSendButton). ! !!AbstractChordMaker methodsFor: 'initialization' stamp: 'nm 1/20/2004 15:01'!initializeArpeggioButton| playButton |playButton_ ScriptableButton new.playButton bounds: (margin + 100@55 corner: 88.5@72); color: Color yellow; label: 'Play arpeggio'; on: #click send: #playArpeggio to: self.^playButton.! !!AbstractChordMaker methodsFor: 'initialization' stamp: 'nm 6/3/2003 19:43'!initializeCloseButton^ ScriptableButton new bounds: (margin + 140@80 corner: 88.5@90); color: Color yellow; label: 'Close'; on: #click send: #close to: self; yourself.! !!AbstractChordMaker methodsFor: 'initialization' stamp: 'nm 6/3/2003 19:43'!initializeDownButton^ ScriptableButton new bounds: (margin + 50@80 corner: 88.5@90); color: Color yellow; label: '8 dn'; on: #click send: #octaveDown to: self; yourself.! !!AbstractChordMaker methodsFor: 'initialization' stamp: 'nm 1/20/2004 15:06'!initializeIntervalTexttextInterval_ TextMorph new.textInterval bounds: (180@130 corner: 200@130); contents: '3M'; color: Color black; borderWidth:1.^textInterval! !!AbstractChordMaker methodsFor: 'initialization' stamp: 'nm 1/20/2004 15:04'!initializeInvertButton^ ScriptableButton new bounds: (margin@105 corner: 88.5@120); color: Color yellow; label: 'Invert'; on: #click send: #invert to: self; yourself.! !!AbstractChordMaker methodsFor: 'initialization' stamp: 'nm 6/3/2003 19:43'!initializeOpenButton^ ScriptableButton new bounds: (margin + 90@80 corner: 88.5@90); color: Color yellow; label: 'Open'; on: #click send: #open to: self; yourself.! !!AbstractChordMaker methodsFor: 'initialization' stamp: 'nm 1/20/2004 15:01'!initializePlayButton^ScriptableButton new bounds: (margin@55 corner: 88.5@72); color: Color yellow; label: 'Play chord'; on: #click send: #playNotes to: self; yourself. ! !!AbstractChordMaker methodsFor: 'initialization' stamp: 'nm 1/20/2004 15:05'!initializeRootButton^ ScriptableButton new bounds: (margin + 50@105 corner: 88.5@120); color: Color yellow; label: 'Root'; on: #click send: #root to: self; yourself.! !!AbstractChordMaker methodsFor: 'initialization' stamp: 'nm 1/20/2004 15:05'!initializeRotateButton^ ScriptableButton new bounds: (margin + 90@105 corner: 88.5@120); color: Color yellow; label: 'Rotate'; on: #click send: #rotate to: self; yourself.! !!AbstractChordMaker methodsFor: 'initialization' stamp: 'nm 1/20/2004 17:04'!initializeSendButton| sendButton |sendButton_ ScriptableButton new.sendButton bounds: (margin+80@175 corner: margin + 20@190); color: Color yellow; label: 'create'; on: #click send: #sendChord to: self.^sendButton.! !!AbstractChordMaker methodsFor: 'initialization' stamp: 'nm 6/3/2003 19:49'!initializeTexttextNotes_ TextMorph new.textNotes contents:' '; bounds: (140@30 corner: 240@80); color: Color black; borderWidth:1.^textNotes! !!AbstractChordMaker methodsFor: 'initialization' stamp: 'nm 1/20/2004 15:03'!initializeTransposeButton^ ScriptableButton new bounds: (margin@130 corner: 88.5@130); color: Color yellow; label: 'Transpose to interval '; on: #click send: #transpose to: self; yourself.! !!AbstractChordMaker methodsFor: 'initialization' stamp: 'nm 6/3/2003 19:42'!initializeUpButton^ ScriptableButton new bounds: (margin@80 corner: 88.5@90); color: Color yellow; label: '8 up'; on: #click send: #octaveUp to: self; yourself.! !!AbstractChordMaker methodsFor: 'initialization' stamp: 'nm 1/20/2004 15:02'!initializeVolumeEditvolumeEdit_ SimpleSliderMorph new bounds: (margin@157 corner: 200@160); value: 0.5.^volumeEdit.! !!AbstractChordMaker methodsFor: 'initialization' stamp: 'nm 1/20/2004 17:07'!initializeWindowwindow_ RectangleMorph new.window position: 1@20; extent: 200@220; color: (Color r: 0.774 g: 0.806 b: 1.0); useRoundedCorners; openInWorld ! !!AbstractChordMaker methodsFor: 'accessing' stamp: 'nm 11/14/2002 12:38'!chord^chord! !!AbstractChordMaker methodsFor: 'accessing' stamp: 'nm 11/14/2002 12:38'!interval^self textInterval contents asString! !!AbstractChordMaker methodsFor: 'accessing' stamp: 'nm 11/14/2002 12:57'!notes^self chordEdit contents asString withBlanksTrimmed! !!AbstractChordMaker methodsFor: 'accessing' stamp: 'nm 11/14/2002 12:38'!textInterval^textInterval! !!AbstractChordMaker class methodsFor: 'as yet unclassified' stamp: 'nm 11/14/2002 12:38'!new^super new initialize.! !!AbstractMusicalNote methodsFor: 'collection' stamp: 'nm 7/13/2002 15:45'!add: aCharacterself named: (self name copyWith: aCharacter) asString! !!AbstractMusicalNote methodsFor: 'collection' stamp: 'nm 7/15/2002 17:31'!allButFirst: anInteger^self name allButFirst: anInteger.! !!AbstractMusicalNote methodsFor: 'collection' stamp: 'nm 7/13/2002 13:25'!at: anInteger^self name at: anInteger.! !!AbstractMusicalNote methodsFor: 'collection' stamp: 'nm 7/13/2002 13:58'!contractTo: anIntegerself name: (self name contractTo: anInteger).! !!AbstractMusicalNote methodsFor: 'collection' stamp: 'nm 7/15/2002 17:29'!first^self name first.! !!AbstractMusicalNote methodsFor: 'collection' stamp: 'nm 7/13/2002 13:25'!size^self name size! !!AbstractMusicalNote methodsFor: 'testing' stamp: 'nm 7/31/2002 17:01'!< aMusicalNote^ self enharmonicIndex < aMusicalNote enharmonicIndex! !!AbstractMusicalNote methodsFor: 'testing' stamp: 'nm 7/31/2002 17:01'!<= aMusicalNote^ self enharmonicIndex <= aMusicalNote enharmonicIndex! !!AbstractMusicalNote methodsFor: 'testing' stamp: 'nm 7/31/2002 17:01'!= aMusicalNote^ self enharmonicIndex = aMusicalNote enharmonicIndex! !!AbstractMusicalNote methodsFor: 'testing' stamp: 'nm 7/31/2002 17:01'!> aMusicalNote^ self enharmonicIndex > aMusicalNote enharmonicIndex! !!AbstractMusicalNote methodsFor: 'testing' stamp: 'nm 7/31/2002 17:02'!>= aMusicalNote^ self enharmonicIndex >= aMusicalNote enharmonicIndex! !!AbstractMusicalNote methodsFor: 'testing' stamp: 'nm 11/17/2002 16:21'!diatonicIntervalTo: anAbstractMusicalNote | scale | scale _ NaturalScale rotateFrom: self copyAsDiatonic. ^ scale indexOf: anAbstractMusicalNote copyAsDiatonic! !!AbstractMusicalNote methodsFor: 'testing' stamp: 'nm 7/13/2002 14:06'!hasAlteration^self size > 1! !!AbstractMusicalNote methodsFor: 'testing' stamp: 'nm 11/13/2002 17:19'!hasAnyFlat^(self hasFlat) or:[self hasDoubleFlat]! !!AbstractMusicalNote methodsFor: 'testing' stamp: 'nm 11/13/2002 17:19'!hasAnySharp^(self hasSharp) or:[self hasDoubleSharp]! !!AbstractMusicalNote methodsFor: 'testing' stamp: 'nm 7/13/2002 14:06'!hasDoubleAlteration^self size = 3! !!AbstractMusicalNote methodsFor: 'testing' stamp: 'nm 7/31/2002 17:33'!hasDoubleFlat^(self hasDoubleAlteration) and: [(self alteration = (Character flat asString,Character flat asString))]! !!AbstractMusicalNote methodsFor: 'testing' stamp: 'nm 8/4/2002 16:24'!hasDoubleSharp^(self hasDoubleAlteration) and: [(self alteration = (Character sharp asString,Character sharp asString))]! !!AbstractMusicalNote methodsFor: 'testing' stamp: 'nm 7/31/2002 17:33'!hasFlat^(self hasSimpleAlteration) and: [(self alteration) = (Character flat)]! !!AbstractMusicalNote methodsFor: 'testing' stamp: 'nm 8/1/2002 13:12'!hasSharp^(self hasSimpleAlteration) and: [(self alteration = Character sharp)]! !!AbstractMusicalNote methodsFor: 'testing' stamp: 'nm 7/13/2002 14:07'!hasSimpleAlteration^self size = 2! !!AbstractMusicalNote methodsFor: 'testing' stamp: 'nm 11/17/2002 16:39'!intervalTo: anAbstractMusicalNote | dia interval st1 st2 |dia_ self diatonicIntervalTo: anAbstractMusicalNote.interval_ MusicalInterval new number: dia; type: #Perfect.st2_ self stepsToNote: anAbstractMusicalNote.st1_ interval stepsTo.^interval type: (interval setTypeForDiatonic: st1 steps: st2).! !!AbstractMusicalNote methodsFor: 'testing' stamp: 'nm 11/16/2002 16:38'!isNatural^NaturalScale includesNote: self.! !!AbstractMusicalNote methodsFor: 'testing' stamp: 'nm 7/13/2002 15:23'!isValidself firstIsValid ifFalse: [self error: 'Invalid note name'].self secondIsValid ifFalse: [self error: 'Invalid alteration'].self thirdIsValid ifFalse: [self error: 'Invalid alteration'].^true.! !!AbstractMusicalNote methodsFor: 'testing' stamp: 'nm 11/17/2002 15:51'!stepsFromDiatonic"sirve para algo?"(self hasDoubleSharp) ifTrue: [^2].(self hasSharp) ifTrue: [^1].(self hasDoubleFlat) ifTrue: [^-2].(self hasFlat) ifTrue: [^-1].^0.! !!AbstractMusicalNote methodsFor: 'testing' stamp: 'nm 11/17/2002 16:39'!stepsToNote: anAbstractMusicalNote | step |step_(anAbstractMusicalNote enharmonicIndex) - (self enharmonicIndex).(step < 0) ifTrue: [step_ step + 12].^step! !!AbstractMusicalNote methodsFor: 'private' stamp: 'nm 7/31/2002 17:12'!enharmonicIndex| idx |idx_0.idx_ DoubleFlatedChromatic indexOf: self. idx > 0 ifTrue:[^idx].idx_ DoubleSharpedChromatic indexOf:self. idx > 0 ifTrue:[^idx].idx_ FlatedChromatic indexOf: self. idx > 0 ifTrue:[^idx].idx_ SharpedChromatic indexOf:self. idx > 0 ifTrue:[^idx].! !!AbstractMusicalNote methodsFor: 'private' stamp: 'nm 12/22/2003 11:35'!firstIsValid^NaturalScale includesName: (self first asLowercase).! !!AbstractMusicalNote methodsFor: 'private' stamp: 'nm 7/13/2002 15:13'!hasValidAlterationAt: anInteger.^((self at:anInteger) = Character sharp) | ((self at:anInteger) = Character flat)! !!AbstractMusicalNote methodsFor: 'private' stamp: 'nm 7/13/2002 15:54'!secondIsValid^(self hasAlteration = false) | ( (self hasAlteration) and: [self hasValidAlterationAt:2]) ! !!AbstractMusicalNote methodsFor: 'private' stamp: 'nm 7/13/2002 15:55'!thirdIsValid^(self hasDoubleAlteration = false) | ( (self hasDoubleAlteration) and: [self hasValidAlterationAt:3]) ! !!AbstractMusicalNote methodsFor: 'printing' stamp: 'nm 7/31/2002 15:01'!printOn: aStreamaStream nextPutAll: self name,' '.! !!AbstractMusicalNote methodsFor: 'copying' stamp: 'nm 11/16/2002 18:39'!copyAsDiatonic^AbstractMusicalNote new name: ((self name first) asString).! !!AbstractMusicalNote methodsFor: 'copying' stamp: 'nm 11/16/2002 18:37'!copyFlated^AbstractMusicalNote new name: (self name,(Character flat asString))! !!AbstractMusicalNote methodsFor: 'copying' stamp: 'nm 11/16/2002 18:37'!copySharped^AbstractMusicalNote new name: (self name,(Character sharp asString))! !!AbstractMusicalNote methodsFor: 'copying' stamp: 'nm 11/13/2002 17:42'!enharmonizeself become: self enharmonic! !!AbstractMusicalNote methodsFor: 'copying' stamp: 'nm 11/16/2002 20:32'!transposeTo: anInterval|scale note |scale_ MusicalScale majorFrom: self.note_ scale notes at: anInterval number.anInterval isMinorOrDiminished ifTrue:[note stepDown].((anInterval type = #Diminished) and:[anInterval number < 4 or:[anInterval number > 5]]) ifTrue: [note stepDown].(anInterval type = #Augmented) ifTrue:[note stepUp].(anInterval type = #SuperAugmented) ifTrue: [note stepUp; stepUp].(anInterval type = #SuperDiminished) ifTrue: [note stepDown; stepDown].^note! !!AbstractMusicalNote methodsFor: 'copying' stamp: 'nm 5/20/2003 17:37'!transposeToString: aString|interval |interval_ MusicalInterval new: aString.^self transposeTo: interval! !!AbstractMusicalNote methodsFor: 'modifying' stamp: 'nm 7/13/2002 14:08'!addFlat(self hasAlteration = false ) | (self hasFlat) ifTrue: [self add: (Character flat)]! !!AbstractMusicalNote methodsFor: 'modifying' stamp: 'nm 11/15/2002 12:20'!addSharpself add: (Character sharp)! !!AbstractMusicalNote methodsFor: 'modifying' stamp: 'nm 11/15/2002 16:50'!asDiatonicself name: ((self name first) asString).! !!AbstractMusicalNote methodsFor: 'modifying' stamp: 'nm 7/13/2002 14:08'!becuadroself hasSimpleAlteration ifTrue: [self asDiatonic].self hasDoubleAlteration ifTrue: [self contractTo: 2].! !!AbstractMusicalNote methodsFor: 'modifying' stamp: 'nm 11/17/2002 18:02'!diatonicTransposeTo: anInterval"no usado"| pos scale alt |alt_ self alteration.scale _ NaturalScale.pos_ scale indexOf: (self asDiatonic) .scale rotate: pos.^AbstractMusicalNote new named: ((scale at: anInterval) asString,(alt asString)).! !!AbstractMusicalNote methodsFor: 'modifying' stamp: 'nm 11/15/2002 16:49'!enharmonic| idx |idx _self enharmonicIndex.(self hasAnyFlat) ifTrue:[^SharpedChromatic at:idx].(self hasAnySharp) ifTrue:[^FlatedChromatic at:idx].! !!AbstractMusicalNote methodsFor: 'modifying' stamp: 'nm 11/16/2002 19:33'!stepDownself hasDoubleFlat ifTrue: [self error: 'Cannot add a flat on a doubleflatted note'].(self hasFlat) | (self isNatural) ifTrue: [self addFlat].(self hasSharp) | (self hasDoubleSharp) ifTrue: [self becuadro]! !!AbstractMusicalNote methodsFor: 'modifying' stamp: 'nm 7/13/2002 14:08'!stepUpself hasDoubleSharp ifTrue: [self error: 'Cannot add a sharp on a doublesharped note'].(self hasSharp) | (self isNatural) ifTrue: [self addSharp].(self hasFlat) | (self hasDoubleFlat) ifTrue: [self becuadro]! !!AbstractMusicalNote methodsFor: 'modifying' stamp: 'nm 11/13/2002 15:16'!transposedTo: anIntervalself become: (self transposeTo: anInterval)! !!AbstractMusicalNote methodsFor: 'accessing' stamp: 'nm 8/4/2002 17:29'!alterationself hasSimpleAlteration ifTrue: [^ self at:2 ].self hasDoubleAlteration ifTrue: [^ self name copyFrom:2 to:3].^$! !!AbstractMusicalNote methodsFor: 'accessing' stamp: 'nm 7/11/2002 14:43'!name^name! !!AbstractMusicalNote methodsFor: 'accessing' stamp: 'nm 1/20/2004 14:19'!name: aString"assigning with validation"name_ aString withBlanksTrimmed asLowercase.self isValid.! !!AbstractMusicalNote methodsFor: 'accessing' stamp: 'nm 10/22/2003 11:45'!named: aString"assigning without validation"name_ aString asLowercase.! !!AbstractMusicalNote methodsFor: 'accessing' stamp: 'nm 6/5/2003 12:38'!pitch"answer absolute pitch if setted, else pitch for name"pitch ifNil: [^AbstractSound pitchForName: (self name, self octave asString)].^pitch! !!AbstractMusicalNote methodsFor: 'accessing' stamp: 'nm 6/4/2003 15:50'!pitch: aFloat"set the pitch of the note. Only needed when using non-temperated tunings"pitch_ aFloat! !!AbstractMusicalNote class methodsFor: 'class initialization' stamp: 'nm 5/17/2003 11:41'!initializeNaturalScale_ MusicalScale natural.FlatedChromatic_ MusicalScale flatedChromatic. SharpedChromatic_ MusicalScale sharpedChromatic. "DoubleFlatedChromatic_ MusicalScale doubleFlatedChromatic.DoubleSharpedChromatic_ MusicalScale doubleSharpedChromatic.""Double... needs Double defined to be constructed".DoubleFlatedChromatic_ MusicalScale new names: #('Dbb' 'Db' 'Ebb' 'Eb' 'Fb' 'Gbb' 'Gb' 'Abb' 'Ab' 'Bbb' 'Bb' 'Cb'); chromaticStructure.DoubleSharpedChromatic_ MusicalScale new names: #('B#' 'C#' 'C##' 'D#' 'D##' 'E#' 'F#' 'F##' 'G#' 'G##' 'A#' 'A##');chromaticStructure.! !!AbstractSound class methodsFor: 'class initialization' stamp: 'nm 6/6/2003 16:42'!initialize "AbstractSound initialize" ScaleFactor _ 2 raisedTo: 15. FloatScaleFactor _ ScaleFactor asFloat. MaxScaledValue _ ((2 raisedTo: 31) // ScaleFactor) - 1. "magnitude of largest scaled value in 32-bits" self tuning:440.! !!AbstractSound class methodsFor: 'class initialization' stamp: 'nm 6/6/2003 16:45'!initializePitches"initialize basic pitches" "generate pitches for c-1 through c0" | bottomB lowB | bottomB _ (Tuning / 32) * (2.0 raisedTo: -10.0 / 12.0). PitchesForBottomOctave _ (1 to: 13) collect: [:i | bottomB * (self temperateSemitoneAt: i)]. lowB:= PitchesForBottomOctave at: 11."generate pitches for b-1 to c0+1 for named notes" LowerPitches_ (1 to: 14) collect: [ :i | lowB * (self temperateSemitoneAt: i)]. TopOfBottomOctave _ PitchesForBottomOctave last. ! !!AbstractSound class methodsFor: 'class initialization' stamp: 'nm 6/6/2003 16:43'!temperateSemitoneAt: anInteger"answer a number to calcular anInteger temperate semitones"^2.0 raisedTo: anInteger asFloat / 12.0! !!AbstractSound class methodsFor: 'class initialization' stamp: 'nm 6/6/2003 16:42'!tuning: aNumber"Set pitch for A4 (Normally 440, but should be different) and initialize basic pitches NM"Tuning_ aNumber.self initializePitches.! !!Character class methodsFor: 'music' stamp: 'nm 7/13/2002 13:18'!flat^$b! !!Character class methodsFor: 'music' stamp: 'nm 7/13/2002 13:18'!sharp^$#! !!Character class methodsFor: 'music' stamp: 'nm 7/13/2002 13:19'!sharpForAbstractSound^$s! !!ChordMaker methodsFor: 'initialization' stamp: 'nm 11/14/2002 12:46'!initializesuper initialize.window addMorph: (self initializeChordEdit).self constructChord.self showNotes. ! !!ChordMaker methodsFor: 'initialization' stamp: 'nm 5/17/2003 12:17'!initializeChordEditchordEdit_ TextMorph new..chordEdit contents: 'C7 ' ; color: Color blue; position: margin@30; extent: 20@80; borderColor: Color black; borderWidth: 2; backgroundColor: Color lightBrown; on: #keyStroke send: #chordEditKeyStroke to: self.^chordEdit.! !!ChordMaker methodsFor: 'initialization' stamp: 'nm 1/20/2004 17:08'!initializeWindowwindow_ RectangleMorph new.window position: 20@20; extent: 220@180; color: (Color r: 0.774 g: 0.806 b: 1.0); useRoundedCorners; openInWorld ! !!ChordMaker methodsFor: 'as yet unclassified' stamp: 'nm 8/6/2002 18:53'!chord^chord! !!ChordMaker methodsFor: 'as yet unclassified' stamp: 'nm 8/9/2002 15:17'!parse| tx |chord_ Chord new parse: (self cells first text).tx_''.chord notes do:[:each | tx_ tx,(each name), (each octave asString),' '].test text: tx.! !!ChordMaker methodsFor: 'actions' stamp: 'nm 11/13/2002 13:32'!chordEditKeyStrokechord_ nil! !!ChordMaker methodsFor: 'actions' stamp: 'nm 11/13/2002 13:31'!constructChordself chord isNil ifTrue:[ self chordOn: self notes].! !!ChordMaker methodsFor: 'accessing' stamp: 'nm 11/13/2002 13:15'!chordEdit^chordEdit! !!ChordMaker methodsFor: 'accessing' stamp: 'nm 7/1/2003 15:33'!chordOn: aStringchord_ Chord new parse: aString asUppercase! !!ChordMaker methodsFor: 'accessing' stamp: 'nm 8/9/2003 17:05'!window^window! !!ChordMaker2 methodsFor: 'actions' stamp: 'nm 11/13/2002 19:30'!chordEditKeyStrokechord_ nil! !!ChordMaker2 methodsFor: 'actions' stamp: 'nm 11/14/2002 11:26'!constructChordself constructScale.chord_ Chord new degree: (self notes) from: scale with: self intervalName.self showNotes! !!ChordMaker2 methodsFor: 'actions' stamp: 'nm 11/16/2002 18:12'!constructScaleself scaleName asCharacter isLowercaseifTrue:[ scale_ MusicalScale minorFromName: self scaleName asUppercase]ifFalse:[ scale_ MusicalScale majorFromName: self scaleName]! !!ChordMaker2 methodsFor: 'actions' stamp: 'nm 11/14/2002 11:21'!scaleEditKeyStrokescale_ nil! !!ChordMaker2 methodsFor: 'initialization' stamp: 'nm 5/17/2003 12:19'!initializesuper initialize.window addMorph: (self initializeChordEdit); addMorph: (self initializeIntervalEdit); addMorph: (self initializeScaleEdit).self constructChord. ! !!ChordMaker2 methodsFor: 'initialization' stamp: 'nm 11/14/2002 11:27'!initializeChordEditchordEdit_ TextMorph new..chordEdit contents: 'I ' ; color: Color blue; position: 20@30; extent: 20@80; borderColor: Color black; borderWidth: 2; backgroundColor: Color lightBrown; on: #keyStroke send: #chordEditKeyStroke to: self.^chordEdit.! !!ChordMaker2 methodsFor: 'initialization' stamp: 'nm 11/14/2002 11:27'!initializeIntervalEditintervalEdit_ TextMorph new..intervalEdit contents: '7 ' ; color: Color blue; position: 60@30; extent: 20@80; borderColor: Color black; borderWidth: 2; backgroundColor: Color lightBrown. ^intervalEdit.! !!ChordMaker2 methodsFor: 'initialization' stamp: 'nm 11/14/2002 11:30'!initializeScaleEditscaleEdit_ TextMorph new..scaleEdit contents: 'C ' ; color: Color blue; position: 120@30; extent: 20@40; borderColor: Color black; borderWidth: 2; backgroundColor: Color lightBrown; on: #keyStroke send: #scaleEditKeyStroke to: self.^scaleEdit.! !!ChordMaker2 methodsFor: 'initialization' stamp: 'nm 5/17/2003 12:20'!initializeWindowwindow_ RectangleMorph new.window position: 20@20; extent: 300@300; color: (Color r: 0.774 g: 0.806 b: 1.0); openInWorld! !!ChordMaker2 methodsFor: 'accessing' stamp: 'nm 11/13/2002 19:30'!chordEdit^chordEdit! !!ChordMaker2 methodsFor: 'accessing' stamp: 'nm 11/13/2002 19:38'!intervalEdit^intervalEdit! !!ChordMaker2 methodsFor: 'accessing' stamp: 'nm 11/14/2002 11:29'!intervalName^self intervalEdit contents asString withBlanksTrimmed! !!ChordMaker2 methodsFor: 'accessing' stamp: 'nm 11/13/2002 19:38'!scaleEdit^scaleEdit! !!ChordMaker2 methodsFor: 'accessing' stamp: 'nm 11/14/2002 11:29'!scaleName^self scaleEdit contents asString withBlanksTrimmed! !!ChordMorph methodsFor: 'accessing' stamp: 'nm 1/20/2004 15:32'!name^name! !!ChordMorph methodsFor: 'accessing' stamp: 'nm 1/20/2004 15:40'!name: aString | label |name:= aString. label := StringMorph contents: aString font: TextStyle defaultFont.""self addMorph: label.label center: self center.self color: (self colorForDegree: aString).! !!ChordMorph methodsFor: 'initialization' stamp: 'nm 1/20/2004 15:32'!colorForDegree: aStringaString = 'I' ifTrue:[^Color lightBlue].aString = 'II' ifTrue:[^Color orange].aString = 'III' ifTrue:[^ Color cyan].aString = 'IV' ifTrue:[^Color orange].aString = 'V' ifTrue:[^ Color red].aString = 'VI' ifTrue:[^ Color cyan].aString = 'VII' ifTrue:[^Color red].^Color cyan.! !!ChordMorph methodsFor: 'initialization' stamp: 'nm 1/20/2004 15:37'!initialize "initialize the receiver" super initialize. "" self extent: 25 @ 25; borderWidth: 1; useRoundedCorners. "" ! !!ChordMorph methodsFor: 'drawing' stamp: 'nm 1/20/2004 15:33'!addGraphic"chord morph don't use graphics"! !!ChordMorph methodsFor: 'event handling' stamp: 'nm 1/20/2004 16:37'!handlesMouseDown: evt(self owner owner isKindOf: ChordPlayerMorph) ifTrue:[^false] ifFalse:[^true]! !!ChordMorph methodsFor: 'event handling' stamp: 'nm 1/20/2004 16:37'!mouseDown: evt(owner owner isKindOf: ChordPaletteMorph) ifTrue:[ self duplicateYourself]ifFalse:[ sound copy play]! !!ChordMorph methodsFor: 'private' stamp: 'nm 1/20/2004 15:32'!duplicateYourself "private - duplicate the receiver and attach the duplicated to the hand" self duplicate openInHand! !!ChordMorph methodsFor: 'playing' stamp: 'nm 1/20/2004 16:30'!playsound play! !!ChordMorph methodsFor: 'playing' stamp: 'nm 1/20/2004 16:31'!playAndWaitUntilDonesound playAndWaitUntilDone! !!ChordMorph class methodsFor: 'instance creation' stamp: 'nm 1/20/2004 15:41'!name: aString "answer an instance of the receiver named aString" ^ self new name: aString! !!ChordPaletteMorph methodsFor: 'accessing' stamp: 'nm 1/20/2004 16:17'!scale^(scales at: scaleIndex) second! !!ChordPaletteMorph methodsFor: 'chords' stamp: 'nm 1/20/2004 16:24'!changeScale(scaleIndex < scales size) ifTrue: [scaleIndex:= scaleIndex + 1] ifFalse: [scaleIndex:= 1].scaleButton label: (scales at: scaleIndex) first.self updateChords.! !!ChordPaletteMorph methodsFor: 'chords' stamp: 'nm 1/20/2004 16:57'!chordFromName: aString ^(ChordMorph new) name: aString; sound: (Chord new degree: aString from: self scale)! !!ChordPaletteMorph methodsFor: 'chords' stamp: 'nm 1/20/2004 16:25'!updateChordschordBar submorphs do:[:each | each sound: (Chord new degree: each name from: self scale) ]! !!ChordPaletteMorph methodsFor: 'initialization' stamp: 'nm 1/20/2004 17:06'!initializesuper initialize.self extent: 180@60; color: Color palePeach; useRoundedCorners.scaleIndex:= 1.self initializeScales.self initializeChords.self initializeScaleButton! !!ChordPaletteMorph methodsFor: 'initialization' stamp: 'nm 1/20/2004 16:22'!initializeChords| chords |chords:= OrderedCollection new.(1 to: 7) do:[:idx | chords add: (self chordFromName: idx romanString)].chordBar:= AlignmentMorph inARow: chords.self addMorph: chordBar.! !!ChordPaletteMorph methodsFor: 'initialization' stamp: 'nm 1/20/2004 16:20'!initializeScaleButtonscaleButton:= ScriptableButton new color: Color yellow; label: 'Major Scale'; left: self left + 5; top: self top + 35; on: #click send: #changeScale to: self; yourself.self addMorph: scaleButton.! !!ChordPaletteMorph methodsFor: 'initialization' stamp: 'nm 1/20/2004 16:13'!initializeScalesscales:= OrderedCollection new.scales add: (Array with: 'Major scale' with: MusicalScale natural); add: (Array with: 'Harmonic Minor scale' with: (MusicalScale harmonicMinorFromName: 'C')); add: (Array with: 'Eolian Minor scale' with: (MusicalScale minorFromName: 'C')); add: (Array with: 'Dorian scale' with: (MusicalScale dorianFromName: 'C')); add: (Array with: 'Phrygian scale' with: (MusicalScale phrygianFromName: 'C')); add: (Array with: 'Lydian scale' with: (MusicalScale lydianFromName: 'C')); add: (Array with: 'Mixo-Lydian scale' with: (MusicalScale mixolydianFromName: 'C')); add: (Array with: 'Locrian scale' with: (MusicalScale locrianFromName: 'C')).! !!ChordPlayerMorph methodsFor: 'private' stamp: 'nm 1/20/2004 16:40'!chordDurs| col prevPos dur chords actPos |col:= OrderedCollection new.chords:= self chordsToPlay.handleDurations ifFalse:[^chords collect:[:each | 1]].prevPos:= ( chords first left + chords first width) .(2 to: chords size) do: [:idx |actPos:= (chords at:idx) left.dur:= ((actPos - prevPos) // 5) * 0.5.col add: dur.prevPos:= actPos + (chords at:idx) width].col add: 1.^col! !!ChordPlayerMorph methodsFor: 'private' stamp: 'nm 8/9/2003 16:40'!chordsToPlay| col |col:= SortedCollection new sortBlock: [:x :y | x left <= y left].chordArea submorphs do: [:each | col add: each].^col! !!ChordPlayerMorph methodsFor: 'playing' stamp: 'nm 1/20/2004 15:49'!clearChordschordArea submorphs do: [:each | each delete].! !!ChordPlayerMorph methodsFor: 'playing' stamp: 'nm 1/20/2004 15:53'!playself chordsToPlay with: self chordDurs do: [:each :eachdur | each sound duration: eachdur. each playAndWaitUntilDone].! !!ChordPlayerMorph methodsFor: 'initialize' stamp: 'nm 1/20/2004 17:06'!initializesuper initialize.handleDurations:= false.self extent: 700@85; left: 100; top: 100; color: Color veryLightGray; borderWidth: 2; useRoundedCorners.self makeControls. ! !!ChordPlayerMorph methodsFor: 'initialize' stamp: 'nm 8/9/2003 16:07'!makeClearButton^ScriptableButton new label: 'Clear'; color: Color yellow; on: #click send: #clearChords to: self; left: self left + 250; top: self top + 55; yourself.! !!ChordPlayerMorph methodsFor: 'initialize' stamp: 'nm 1/20/2004 17:09'!makeControlschordArea:= PasteUpMorph new width: self width-10; height: 40; top:self top + 5; left: self left +5; color: Color lightBlue; beSticky; useRoundedCorners.self addMorph: chordArea.buttonArea:= (PasteUpMorph new) width: self width-10; height: 32; top:self top + 50; left: self left +5; color: Color white; beSticky; useRoundedCorners.buttonArea addMorph: self makeClearButton; addMorph: self makePlayButton.self addMorph: buttonArea. ! !!ChordPlayerMorph methodsFor: 'initialize' stamp: 'nm 1/20/2004 15:00'!makePlayButton^ScriptableButton new label: 'Play'; color: Color yellow; on: #click send: #play to: self; left: self left + 10; top: self top + 55; yourself.! !!ChordPlayerMorph methodsFor: 'initialize' stamp: 'nm 8/9/2003 17:04'!withChordMakerChordMaker new window top:200 ! !!ChordPlayerMorph methodsFor: 'accessing' stamp: 'nm 8/9/2003 16:37'!chordArea^chordArea! !!ChordPlayerMorph methodsFor: 'submorphs-accessing' stamp: 'nm 8/8/2003 14:56'!addChord: aChordMorphplayer addMorph: aChordMorph! !!ChordPlayerMorph methodsFor: 'menus' stamp: 'nm 1/20/2004 16:42'!addCustomMenuItems: aCustomMenu hand: aHandMorphsuper addCustomMenuItems: aCustomMenu hand: aHandMorph.aCustomMenu addUpdating: #handleDurationsString target: self action: #toggleHandleDurations.! !!ChordPlayerMorph methodsFor: 'menus' stamp: 'nm 1/20/2004 16:43'!handleDurationsString^(handleDurationsifTrue: [''] ifFalse: ['']), 'duration proportional to size'! !!ChordPlayerMorph methodsFor: 'menus' stamp: 'nm 1/20/2004 16:44'!toggleHandleDurationshandleDurations ifTrue:[ handleDurations:= false] ifFalse:[handleDurations:= true]! !!Collection methodsFor: 'enumerating' stamp: 'nm 6/24/2003 19:04'!rotate: anInteger^(self allButFirst:anInteger-1), (self first: anInteger - 1) "NM"! !!Measure methodsFor: 'inquiring' stamp: 'nm 5/17/2003 16:08'!durationForTempo: aTempo"real duration of self for aTempo"^(aTempo realDuration) * self quarterDuration! !!Measure methodsFor: 'inquiring' stamp: 'nm 5/17/2003 16:06'!quarterBeatDuration"duration of a beat relative to quarter note"^(self quarterDuration / beats) asFloat! !!Measure methodsFor: 'inquiring' stamp: 'nm 5/17/2003 16:07'!quarterDuration"self duration relative to quarter note"^(numerator / denominator) * 4! !!Measure methodsFor: 'testing' stamp: 'nm 5/17/2003 15:01'!isCompound^(numerator = 6) | (numerator = 9) | (numerator = 12)! !!Measure methodsFor: 'priting' stamp: 'nm 5/17/2003 15:11'!printOn: aStreamaStream nextPutAll: numerator asString,'/', denominator asString,' (beats=', beats asString,' division= ',division asString,')'.! !!Measure methodsFor: 'accessing' stamp: 'nm 11/17/2002 18:10'!beats^beats! !!Measure methodsFor: 'accessing' stamp: 'nm 5/17/2003 15:09'!denominator: anIntegerdenominator_ anInteger.self setBeatsAndDivision! !!Measure methodsFor: 'accessing' stamp: 'nm 5/17/2003 15:08'!division^ division! !!Measure methodsFor: 'accessing' stamp: 'nm 5/17/2003 15:09'!numerator: anIntegernumerator_ anInteger.self setBeatsAndDivision! !!Measure methodsFor: 'accessing' stamp: 'nm 5/17/2003 15:09'!setBeatsAndDivision(denominator notNil and:[numerator notNil]) ifTrue:[self isCompound ifTrue:[beats:= (numerator / 3). division:=3] ifFalse:[beats:= numerator. division:=2]]! !!Measure class methodsFor: 'as yet unclassified' stamp: 'nm 5/17/2003 14:51'!new: aString^super newnumerator: (aString copyUpTo: $/) asInteger ;denominator: (aString copyAfter: $/) asInteger! !!Metronomo methodsFor: 'actions' stamp: 'nm 11/17/2002 18:22'!play: unosSegundos|segWait T|T:=0.segWait:= 60 / (pulso value).[[T 5]]) ifTrue:[stp_ stp -1].(self type = #Augmented) ifTrue:[stp_ stp + 1].(self type = #SuperAugmented) ifTrue: [stp_ stp + 2].(self type = #SuperDiminished) ifTrue: [stp_ stp - 2].^stp! !!MusicalInterval methodsFor: 'testing' stamp: 'nm 11/17/2002 16:30'!stepsToXXX"deber’a usarlo AbstrtactMusicalNote #transposeToString pero no lo usa"| stp |stp_0.self isMinorOrDiminished ifTrue:[stp_ stp -1].((self type = #Diminished) and:[(self number < 4) or:[self number > 5]]) ifTrue:[stp_ stp -1].(self type = #Augmented) ifTrue:[stp_ stp + 1].(self type = #SuperAugmented) ifTrue: [stp_ stp + 2].(self type = #SuperDiminished) ifTrue: [stp_ stp - 2].^stp! !!MusicalInterval methodsFor: 'accessing' stamp: 'nm 11/16/2002 18:45'!number^number! !!MusicalInterval methodsFor: 'accessing' stamp: 'nm 11/16/2002 19:14'!number: anIntegernumber_ anInteger.self type notNil ifTrue: [self setSteps]! !!MusicalInterval methodsFor: 'accessing' stamp: 'nm 11/16/2002 19:25'!setSteps| num |num_ NaturalScale stepsTo: self number.((type = #Minor) or:[type = #Diminished]) ifTrue: [num_ num -1].(type = #Augmented) ifTrue: [num_ num + 1].(type = #SuperAugmented) ifTrue: [num_ num + 2].(type = #SuperDiminished) ifTrue: [num_ num - 2].self steps: num.! !!MusicalInterval methodsFor: 'accessing' stamp: 'nm 11/16/2002 19:13'!steps^steps! !!MusicalInterval methodsFor: 'accessing' stamp: 'nm 11/16/2002 19:13'!steps: anIntegersteps_ anInteger! !!MusicalInterval methodsFor: 'accessing' stamp: 'nm 11/16/2002 18:46'!type^type! !!MusicalInterval methodsFor: 'accessing' stamp: 'nm 11/16/2002 19:14'!type: aSymboltype_ aSymbol.self number notNil ifTrue: [self setSteps]! !!MusicalInterval methodsFor: 'printing' stamp: 'nm 11/16/2002 19:19'!printOn: aStreamaStream print: self number; nextPutAll:' '; print: self type; nextPutAll:' '; print: self steps.! !!MusicalInterval methodsFor: 'private' stamp: 'nm 11/17/2002 15:05'!setTypeForDiatonic: anInteger steps: otherInteger| num |num_ otherInteger - anInteger.(num = 0) ifTrue: [ (self numberIsPerfect) ifTrue: [^#Perfect] ifFalse:[^#Major]].(num = -1) ifTrue: [ (self numberIsPerfect) ifTrue: [^#Diminished] ifFalse:[^#Minor]].(num = 1) ifTrue: [^#Augmented].(num = 2) ifTrue: [^#SuperAugmented].(num = -2) ifTrue: [ (self numberIsPerfect) ifTrue: [^#SuperDiminished] ifFalse:[^#Diminished]].! !!MusicalInterval methodsFor: 'private' stamp: 'nm 11/16/2002 19:13'!validate! !!MusicalInterval class methodsFor: 'instance creation' stamp: 'nm 5/20/2003 18:19'!augmentedFourth^self new: '4a'! !!MusicalInterval class methodsFor: 'instance creation' stamp: 'nm 5/20/2003 18:18'!diminishedFifth^self new: '5d'! !!MusicalInterval class methodsFor: 'instance creation' stamp: 'nm 5/20/2003 18:17'!majorSecond^self new: '2M'! !!MusicalInterval class methodsFor: 'instance creation' stamp: 'nm 5/20/2003 18:19'!majorSeventh^self new: '7M'! !!MusicalInterval class methodsFor: 'instance creation' stamp: 'nm 5/20/2003 18:19'!majorSixth^self new: '6M'! !!MusicalInterval class methodsFor: 'instance creation' stamp: 'nm 5/20/2003 18:17'!majorThird^self new: '3M'! !!MusicalInterval class methodsFor: 'instance creation' stamp: 'nm 5/20/2003 18:17'!minorSecond^self new: '2m'! !!MusicalInterval class methodsFor: 'instance creation' stamp: 'nm 5/20/2003 18:19'!minorSeventh^self new: '7m'! !!MusicalInterval class methodsFor: 'instance creation' stamp: 'nm 5/20/2003 18:19'!minorSixth^self new: '6m'! !!MusicalInterval class methodsFor: 'instance creation' stamp: 'nm 5/20/2003 18:18'!minorThird^self new: '3m'! !!MusicalInterval class methodsFor: 'instance creation' stamp: 'nm 5/20/2003 17:36'!new: aString|st type number |number_ aString first asString asInteger.st_ aString copyFrom:2 to: (aString size).(st first=$M) ifTrue:[type_ #Major].(st first=$m) ifTrue: [type_ #Minor].(st first asUppercase =$A) ifTrue: [type_ #Augmented].(st first asUppercase =$D) ifTrue: [type_ #Diminished].((st first asUppercase =$P) or:[(st first asUppercase =$J)]) ifTrue: [type_ #Perfect].(st asUppercase = 'SA') ifTrue: [type_ #SuperAugmented].(st asUppercase = 'SD') ifTrue: [type_ #SuperDiminished].(type isNil) | (number < 1) | (number > 15) ifTrue: [self error: 'Invalid interval'].^super new number: number; type: type! !!MusicalInterval class methodsFor: 'instance creation' stamp: 'nm 5/20/2003 18:18'!perfectFifth^self new: '5j'! !!MusicalInterval class methodsFor: 'instance creation' stamp: 'nm 5/20/2003 18:18'!perfectFourth^self new: '4j'! !!MusicalInterval class methodsFor: 'class initialization' stamp: 'nm 11/16/2002 20:48'!initializeNaturalScale_ MusicalScale natural.InvertedIntervals _ Dictionary new. InvertedIntervals at: #Major put:#Minor; at: #Minor put:#Major; at: #Diminished put:#Augmented; at: #Augmented put:#Diminished; at: #SuperDiminished put:#SuperAugmented; at: #SuperAugmented put:#SuperDiminished; at: #Perfect put: #Perfect.! !!MusicalNote methodsFor: 'accessing' stamp: 'nm 1/20/2004 14:20'!duration"answer realduration, i.e., nominal duration minus articulation"^duration! !!MusicalNote methodsFor: 'accessing' stamp: 'nm 5/18/2003 17:09'!duration: aNumberduration_ aNumber! !!MusicalNote methodsFor: 'accessing' stamp: 'nm 7/31/2002 14:57'!octave^octave! !!MusicalNote methodsFor: 'accessing' stamp: 'nm 7/31/2002 14:57'!octave: anIntegeroctave_ anInteger! !!MusicalNote methodsFor: 'accessing' stamp: 'nm 5/18/2003 18:04'!rest"answer real rest time, i.e., absolute duration. if rest, duration is negative).if note, real rest is articulation"self isRest ifTrue: [^duration abs] ifFalse: [^articulation]! !!MusicalNote methodsFor: 'initialization' stamp: 'nm 1/20/2004 13:03'!canPlayself class askCanPlay ifFalse:[self error: 'Sounds are not enabled.'].! !!MusicalNote methodsFor: 'initialization' stamp: 'nm 1/20/2004 12:44'!initializeself canPlay.octave_3.duration_ 0.5."articulation_ 0."! !!MusicalNote methodsFor: 'printing' stamp: 'nm 6/5/2003 17:29'!printOn: aStreamaStream nextPutAll: name; print: octave; nextPutAll: ' '; print: duration; nextPutAll: ' '. ! !!MusicalNote methodsFor: 'testing' stamp: 'nm 7/31/2002 17:19'!< aMusicalNote^(self octave < aMusicalNote octave) or:[(self octave = aMusicalNote octave) & (super < aMusicalNote)]! !!MusicalNote methodsFor: 'testing' stamp: 'nm 7/31/2002 17:23'!<= aMusicalNote^ (self < aMusicalNote) or:[(self = aMusicalNote)]! !!MusicalNote methodsFor: 'testing' stamp: 'nm 7/31/2002 17:17'!= aMusicalNote^(self octave = aMusicalNote octave) & (super = aMusicalNote)! !!MusicalNote methodsFor: 'testing' stamp: 'nm 7/31/2002 17:20'!> aMusicalNote^(self octave > aMusicalNote octave) or:[(self octave = aMusicalNote octave) & (super > aMusicalNote)]! !!MusicalNote methodsFor: 'testing' stamp: 'nm 7/31/2002 17:23'!>= aMusicalNote^ (self > aMusicalNote) or:[(self = aMusicalNote)]! !!MusicalNote methodsFor: 'testing' stamp: 'nm 12/22/2003 14:11'!greaterThan: aMusicalNote^super >aMusicalNote! !!MusicalNote methodsFor: 'testing' stamp: 'nm 5/18/2003 17:35'!isNotRest^self isRest not! !!MusicalNote methodsFor: 'testing' stamp: 'nm 5/18/2003 16:41'!isRest^duration negative! !!MusicalNote methodsFor: 'melodic transformation' stamp: 'nm 11/13/2002 18:59'!enharmonic^MusicalNote new name: (super enharmonic name)! !!MusicalNote methodsFor: 'melodic transformation' stamp: 'nm 7/31/2002 17:38'!octaveDownself octave: self octave - 1! !!MusicalNote methodsFor: 'melodic transformation' stamp: 'nm 7/31/2002 17:38'!octaveUpself octave: self octave + 1! !!MusicalNote methodsFor: 'melodic transformation' stamp: 'nm 5/20/2003 18:11'!transposeTo: anInterval"hay que usar copy en lugar de tanta variable"| newnote |newnote_ super transposeTo: anInterval.((newnote < self ) and:[ self name ~= 'C']) ifTrue: [^MusicalNote new name: newnote name; octaveUp; duration: self duration] ifFalse: [^MusicalNote new name: newnote name; octave: self octave; duration: self duration]! !!MusicalNote methodsFor: 'playing' stamp: 'nm 10/22/2003 11:50'!play"for testing only"self playOn: FMSound clarinet loudness: 0.5. ! !!MusicalNote methodsFor: 'playing' stamp: 'nm 6/5/2003 13:40'!playOn: anAbstractSound"for testing only"(anAbstractSound setPitch: self pitch dur: self duration loudness: 0.5) play! !!MusicalNote methodsFor: 'playing' stamp: 'nm 6/5/2003 13:29'!playOn: anAbstractSound duration: aNumber loudness: otherNumber"no va"(anAbstractSound setPitch: self pitch dur: aNumber loudness: otherNumber) play! !!MusicalNote methodsFor: 'playing' stamp: 'nm 6/5/2003 13:40'!playOn: anAbstractSound loudness: anInteger"for testing only"(anAbstractSound setPitch: self pitch dur: self duration loudness: anInteger) play! !!MusicalNote methodsFor: 'playing' stamp: 'nm 6/5/2003 13:40'!prepareToPlayArticulation: anInteger"anwser an array with a rest for playing melodies"^Array with: #rest with: anInteger! !!MusicalNote methodsFor: 'playing' stamp: 'nm 7/1/2003 15:29'!prepareToPlayDuration: anInteger loudness: aNumber"anwser an array with self for playing melodies"^Array with: (self name asLowercase,self octave asString) with: anInteger with:aNumber! !!MusicalNote methodsFor: 'playing' stamp: 'nm 6/5/2003 13:41'!prepareToPlayRest"anwser an array with a rest for playing melodies"^Array with: #rest with: self duration abs! !!MusicalNote class methodsFor: 'as yet unclassified' stamp: 'nm 1/20/2004 13:36'!askCanPlayPreferences soundsEnabled ifFalse: [(CustomMenu new) title: 'Sounds are not enabled'; addLine; add: 'Enable sounds' action: self enableSounds; add: 'Cancel' action: nil; startUp].^Preferences soundsEnabled.! !!MusicalNote class methodsFor: 'as yet unclassified' stamp: 'nm 1/20/2004 13:03'!disableSoundsPreferences disable: #soundsEnabled! !!MusicalNote class methodsFor: 'as yet unclassified' stamp: 'nm 1/20/2004 13:03'!enableSoundsPreferences enable: #soundsEnabled! !!MusicalNote class methodsFor: 'as yet unclassified' stamp: 'nm 11/16/2002 21:18'!new^super new initialize. ! !!MusicalScale methodsFor: 'testing' stamp: 'nm 7/13/2002 14:52'!includesName: aCharacter^self notes anySatisfy: [:each | (each name at:1) = aCharacter]! !!MusicalScale methodsFor: 'testing' stamp: 'nm 7/13/2002 14:50'!includesNote: aNote^self notes anySatisfy: [:each | each name = aNote name]! !!MusicalScale methodsFor: 'collection' stamp: 'nm 7/20/2002 16:54'!add: aMusicalNotenotes add: aMusicalNote! !!MusicalScale methodsFor: 'collection' stamp: 'nm 7/13/2002 15:58'!at: anInteger^self notes at: anInteger! !!MusicalScale methodsFor: 'collection' stamp: 'nm 11/16/2002 14:44'!atWrap: anInteger^self notes atWrap: anInteger! !!MusicalScale methodsFor: 'collection' stamp: 'nm 11/16/2002 17:35'!first^self notes first! !!MusicalScale methodsFor: 'collection' stamp: 'nm 7/31/2002 17:10'!indexOf: aNote|idx|idx_ 1.self notes do: [:each | each name = aNote name ifTrue:[^idx].idx_idx+1].^0.! !!MusicalScale methodsFor: 'collection' stamp: 'nm 11/16/2002 13:23'!rotate: anIntegernotes_ self notes rotate: anInteger.steps_ self steps rotate: anInteger! !!MusicalScale methodsFor: 'private' stamp: 'nm 11/16/2002 15:30'!allFlatedself notes do: [:each | each addFlat] ! !!MusicalScale methodsFor: 'private' stamp: 'nm 11/16/2002 15:31'!allSharpedself notes do: [:each | each addSharp] ! !!MusicalScale methodsFor: 'private' stamp: 'nm 11/16/2002 17:32'!chromaticStructureself steps: #(1 1 1 1 1 1 1 1 1 1 1 1)! !!MusicalScale methodsFor: 'private' stamp: 'nm 11/16/2002 16:45'!noteAndStepDownAt: anInteger(self at: anInteger) stepDown.self stepDownAt: (anInteger -1).self stepUpAt: anInteger.! !!MusicalScale methodsFor: 'private' stamp: 'nm 11/16/2002 17:20'!noteAndStepUpAt: anInteger(self at: anInteger) stepUp.self stepUpAt: (anInteger -1).self stepDownAt: anInteger.! !!MusicalScale methodsFor: 'private' stamp: 'nm 10/26/2003 17:50'!rotateFrom: aNote| idx natNot |natNot_ (AbstractMusicalNote new named: aNote name) asDiatonic.idx_ self indexOf: natNot.self rotate: idx.! !!MusicalScale methodsFor: 'private' stamp: 'nm 11/16/2002 17:46'!sortself notes: (self notes asSortedCollection)! !!MusicalScale methodsFor: 'private' stamp: 'nm 11/16/2002 14:47'!stepDownAt: anIntegerself steps atWrap: anInteger put:(self stepsAt: anInteger)-1! !!MusicalScale methodsFor: 'private' stamp: 'nm 11/16/2002 14:45'!stepUpAt: anIntegerself steps atWrap: anInteger put:(self stepsAt: anInteger)+1! !!MusicalScale methodsFor: 'printing' stamp: 'nm 11/16/2002 14:31'!printOn: aStreamnotes do: [:each | each printOn: aStream].steps do: [:each | aStream nextPutAll:' '; print: each].! !!MusicalScale methodsFor: 'initialization' stamp: 'nm 5/17/2003 11:37'!initializenotes_OrderedCollection new.steps_OrderedCollection new.! !!MusicalScale methodsFor: 'accessing' stamp: 'nm 7/31/2002 15:00'!names: aCollectionaCollection do:[: each | self add:( AbstractMusicalNote new named: each)]! !!MusicalScale methodsFor: 'accessing' stamp: 'nm 7/11/2002 16:08'!notes^notes! !!MusicalScale methodsFor: 'accessing' stamp: 'nm 7/11/2002 17:26'!notes: anOrderedCollectionnotes_ anOrderedCollection.! !!MusicalScale methodsFor: 'accessing' stamp: 'nm 11/16/2002 13:29'!steps^steps! !!MusicalScale methodsFor: 'accessing' stamp: 'nm 11/16/2002 13:20'!steps: anArraysteps_ anArray! !!MusicalScale methodsFor: 'accessing' stamp: 'nm 11/16/2002 14:45'!stepsAt: anInteger^self steps atWrap: anInteger! !!MusicalScale methodsFor: 'accessing' stamp: 'nm 11/16/2002 19:25'!stepsTo: anInteger|sum|sum_ 0.(1 to: anInteger - 1) do: [:idx | sum_ sum + (self stepsAt: idx)].^sum.! !!MusicalScale methodsFor: 'accessing' stamp: 'nm 11/15/2002 11:46'!totalSteps^self notes size! !!MusicalScale methodsFor: 'playing' stamp: 'nm 1/20/2004 14:19'!asMelody| mel octave |"make a melody with my notes, with default duration and octave""OJO. El cambio de octava deber’a estar en otra parte"mel:= Melody new.octave:= 4.self notes do: [:each | mel addNote: ((MusicalNote new named: each name) octave:octave; duration: 0.4). (each name='b') ifTrue:[octave:= octave + 1]].^mel! !!MusicalScale methodsFor: 'playing' stamp: 'nm 10/22/2003 11:35'!play| mel |mel:= self asMelody. mel addNote: (mel notes first copy octave:5).mel play! !!MusicalScale methodsFor: 'playing' stamp: 'nm 10/22/2003 11:35'!playOn: anAbstractSound| mel |mel:= self asMelody. mel addNote: (mel notes first copy octave:5).mel playOn: anAbstractSound! !!MusicalScale class methodsFor: 'samples' stamp: 'nm 11/16/2002 17:21'!dorianFrom: aNote| scale |scale_ self minorFrom: aNote.^scale noteAndStepUpAt: 6.! !!MusicalScale class methodsFor: 'samples' stamp: 'nm 11/16/2002 17:22'!dorianFromName: aString| note |note_ MusicalNote new name: aString.^self dorianFrom: note.! !!MusicalScale class methodsFor: 'samples' stamp: 'nm 11/16/2002 17:15'!harmonicMinorFrom: aNote| scale |scale_ self melodicMinorFrom: aNote.^scale noteAndStepDownAt: 6.! !!MusicalScale class methodsFor: 'samples' stamp: 'nm 11/16/2002 17:16'!harmonicMinorFromName: aString| note |note_ MusicalNote new name: aString.^self harmonicMinorFrom: note.! !!MusicalScale class methodsFor: 'samples' stamp: 'nm 5/20/2003 15:31'!locrianFrom: aNote| scale |scale_ self phrygianFrom: aNote.^scale noteAndStepDownAt: 5.! !!MusicalScale class methodsFor: 'samples' stamp: 'nm 11/16/2002 17:25'!locrianFromName: aString| note |note_ MusicalNote new name: aString.^self locrianFrom: note.! !!MusicalScale class methodsFor: 'samples' stamp: 'nm 5/20/2003 15:31'!lydianFrom: aNote| scale |scale_ self majorFrom: aNote.^scale noteAndStepUpAt: 4.! !!MusicalScale class methodsFor: 'samples' stamp: 'nm 5/20/2003 15:31'!lydianFromName: aString| note |note_ MusicalNote new name: aString.^self lydianFrom: note.! !!MusicalScale class methodsFor: 'samples' stamp: 'nm 1/20/2004 14:54'!majorPentatonic^super new initialize; names: #('C' 'D' 'E' 'G' 'A' ); steps: #(2 2 4 2 )! !!MusicalScale class methodsFor: 'samples' stamp: 'nm 11/16/2002 17:14'!melodicMinorFrom: aNote| scale |scale_ self majorFrom: aNote.^scale noteAndStepDownAt: 3.! !!MusicalScale class methodsFor: 'samples' stamp: 'nm 11/16/2002 16:35'!melodicMinorFromName: aString| note |note_ MusicalNote new name: aString.^self melodicMinorFrom: note.! !!MusicalScale class methodsFor: 'samples' stamp: 'nm 11/16/2002 17:17'!minorFrom: aNote| scale |scale_ self harmonicMinorFrom: aNote.^scale noteAndStepDownAt: 7.! !!MusicalScale class methodsFor: 'samples' stamp: 'nm 11/16/2002 17:17'!minorFromName: aString| note |note_ MusicalNote new name: aString.^self minorFrom: note.! !!MusicalScale class methodsFor: 'samples' stamp: 'nm 1/20/2004 14:57'!minorPentatonic^super new initialize; names: #('C' 'Eb' 'F' 'G' 'Bb'); steps: #(4 2 2 4)! !!MusicalScale class methodsFor: 'samples' stamp: 'nm 5/20/2003 15:34'!mixolydianFrom: aNote| scale |scale_ self majorFrom: aNote.^scale noteAndStepDownAt: 7.! !!MusicalScale class methodsFor: 'samples' stamp: 'nm 5/20/2003 15:34'!mixolydianFromName: aString| note |note_ MusicalNote new name: aString.^self mixolydianFrom: note.! !!MusicalScale class methodsFor: 'samples' stamp: 'nm 5/20/2003 15:32'!phrygianFrom: aNote| scale |scale_ self minorFrom: aNote.^scale noteAndStepDownAt: 2.! !!MusicalScale class methodsFor: 'samples' stamp: 'nm 5/20/2003 15:30'!phrygianFromName: aString| note |note_ MusicalNote new name: aString.^self phrygianFrom: note.! !!MusicalScale class methodsFor: 'instance creation' stamp: 'nm 5/17/2003 11:43'!doubleFlatedChromatic| scale1 scale2 newScale |scale1_self naturalFifthCircle allFlated.scale2_self naturalFifthCircle allFlated; allFlated.scale2 notes removeAt:7.scale2 notes removeAt:6.newScale_ self new.newScale notes addAll: scale1 notes.newScale notes addAll: scale2 notes.newScale chromaticStructure.^newScale sort.! !!MusicalScale class methodsFor: 'instance creation' stamp: 'nm 5/17/2003 11:43'!doubleSharpedChromatic| scale1 scale2 newScale |scale1_self naturalFifthCircle allSharped.scale2_self naturalFifthCircle allSharped; allSharped.scale2 notes removeAt:5.scale2 notes removeAt:4.newScale_ self new.newScale notes addAll: scale1 notes.newScale notes addAll: scale2 notes.newScale chromaticStructure.^newScale sort.! !!MusicalScale class methodsFor: 'instance creation' stamp: 'nm 11/16/2002 18:37'!flatedChromatic| col scale|col_ OrderedCollection new.scale_ self natural.(1 to: scale totalSteps) do: [:idx | col add: (scale at:idx). ((scale stepsAt:idx) = 2) ifTrue:[ col add: (scale at:idx+1) copyFlated]].scale notes: col.^scale chromaticStructure! !!MusicalScale class methodsFor: 'instance creation' stamp: 'nm 11/16/2002 17:12'!majorFrom: aNote|natScale newScale natNote idx |natScale_ self natural.natNote_ aNote copy."escalas con dobles sostenidos o dobles bemoles"idx_ (natScale indexOf: natNote asDiatonic).((aNote hasFlat) and: [(natScale stepsAt:(idx -1)) = 1]) ifTrue: [newScale_ self normalMajorFrom: natNote. newScale allFlated.^newScale].(aNote hasSharp) ifTrue: [newScale_ self normalMajorFrom: natNote. newScale allSharped.^newScale].^self normalMajorFrom: aNote.! !!MusicalScale class methodsFor: 'instance creation' stamp: 'nm 11/15/2002 18:37'!majorFromName: aString| note |note_ MusicalNote new name: aString.^self majorFrom: note.! !!MusicalScale class methodsFor: 'instance creation' stamp: 'nm 11/16/2002 13:21'!natural^super new initialize; names: #('C' 'D' 'E' 'F' 'G' 'A' 'B' ); steps: #(2 2 1 2 2 2 1)! !!MusicalScale class methodsFor: 'instance creation' stamp: 'nm 11/16/2002 17:33'!naturalFifthCircle| scale col|scale_ self natural.col_ OrderedCollection new.col addAll: ((1 to: scale totalSteps) collect: [:each | (scale rotate:5) first]).scale notes: col.^scale steps: #(7 7 7 7 7 7 7)! !!MusicalScale class methodsFor: 'instance creation' stamp: 'nm 11/16/2002 17:33'!naturalFourthCircle| scale col|scale_ self natural.col_ OrderedCollection new.col addAll: ((1 to: scale totalSteps) collect: [:each | (scale rotate:4) first]).scale notes: col.^scale steps: #(5 5 5 5 5 5 5)! !!MusicalScale class methodsFor: 'instance creation' stamp: 'nm 7/13/2002 14:11'!new^super new initialize! !!MusicalScale class methodsFor: 'instance creation' stamp: 'nm 11/16/2002 15:31'!normalMajorFrom: aNote|natScale newScale idx|natScale_ self natural.newScale_ natScale copy.newScale rotateFrom: aNote.aNote hasFlat ifTrue: [newScale stepUpAt:1].aNote hasSharp ifTrue: [newScale stepDownAt:1].idx_ 0.newScale steps with: natScale steps do: [:eachnat :eachnew| idx_ idx + 1. eachnat < eachnew ifTrue: [(newScale atWrap:idx+1) addSharp. newScale stepUpAt:idx; stepDownAt: idx +1]. eachnat > eachnew ifTrue: [(newScale atWrap:idx+1) addFlat.newScale stepDownAt:idx; stepUpAt: idx +1]].aNote hasFlat ifTrue: [newScale stepDownAt:1].aNote hasSharp ifTrue: [newScale stepUpAt:1].^newScale! !!MusicalScale class methodsFor: 'instance creation' stamp: 'nm 11/16/2002 18:38'!sharpedChromatic| col scale|col_ OrderedCollection new.scale_self natural.(1 to: scale totalSteps) do: [:idx | col add: (scale at:idx). ((scale stepsAt:idx) = 2) ifTrue:[ col add: (scale at:idx) copySharped]].scale notes: col.^scale chromaticStructure! !!MusicalStream methodsFor: 'rythmic transformation' stamp: 'nm 11/20/2002 19:05'!setDuration: anIntegerself notes do: [:each | each duration: anInteger]! !!MusicalStream methodsFor: 'rythmic transformation' stamp: 'nm 11/17/2002 18:29'!tempoTo: aNumberself notes do: [:each | each duration: (each duration * aNumber)]! !!MusicalStream methodsFor: 'melodic transformation' stamp: 'nm 11/17/2002 15:21'!intervals| col |col_ OrderedCollection new.(1 to: (self notes size-1)) do: [:idx | col add: ((self notes at: idx) intervalTo:(self notes at: idx+1))].^col ! !!MusicalStream methodsFor: 'melodic transformation' stamp: 'nm 11/17/2002 17:42'!invert| intervals|intervals_ self invertedIntervals.^MusicalStream fromNote: (self notes first) withIntervals: intervals. ! !!MusicalStream methodsFor: 'melodic transformation' stamp: 'nm 11/17/2002 17:21'!invertedIntervals^self intervals collect: [:each | each invert] ! !!MusicalStream methodsFor: 'melodic transformation' stamp: 'nm 11/16/2002 21:04'!octaveDownnotes do:[ :each | each octaveDown]! !!MusicalStream methodsFor: 'melodic transformation' stamp: 'nm 11/16/2002 21:04'!octaveUpnotes do:[ :each | each octaveUp]! !!MusicalStream methodsFor: 'melodic transformation' stamp: 'nm 11/17/2002 17:42'!reverse^MusicalStream new notes: self notes reverse! !!MusicalStream methodsFor: 'melodic transformation' stamp: 'nm 11/17/2002 17:52'!reverseAndInvert^self reverse invert ! !!MusicalStream methodsFor: 'melodic transformation' stamp: 'nm 11/17/2002 17:58'!reverseAndInvertFromFirst^MusicalStream fromNote: (self first) withIntervals: (self reverse invert intervals)! !!MusicalStream methodsFor: 'melodic transformation' stamp: 'nm 11/16/2002 21:05'!rotate: anIntegernotes_ notes rotate: anInteger! !!MusicalStream methodsFor: 'melodic transformation' stamp: 'nm 5/20/2003 11:18'!sameOctave: anInteger"all notes to octave anInteger"self notes do: [:each | each octave: anInteger]! !!MusicalStream methodsFor: 'melodic transformation' stamp: 'nm 12/22/2003 14:53'!sortnotes_ (self notes asSortedCollection sortBlock: [:one :two | one <= two ]) asOrderedCollection.! !!MusicalStream methodsFor: 'melodic transformation' stamp: 'nm 5/20/2003 17:37'!transposeTo: anIntervalOrString| interval |anIntervalOrString isString ifFalse:[interval:= anIntervalOrString] ifTrue: [interval_ MusicalInterval new: anIntervalOrString].self notes do: [:each | each transposedTo: interval].! !!MusicalStream methodsFor: 'printing' stamp: 'nm 11/16/2002 21:01'!printOn: aStreamnotes do: [:each | each printOn: aStream].! !!MusicalStream methodsFor: 'inquiring' stamp: 'nm 5/18/2003 18:22'!countNotes^notes size! !!MusicalStream methodsFor: 'accessing' stamp: 'nm 5/18/2003 17:12'!addNote: anAbstractMusicalNotenotes add: anAbstractMusicalNote ! !!MusicalStream methodsFor: 'accessing' stamp: 'nm 5/18/2003 17:12'!addNoteNamed: aStringself addNote: (MusicalNote new named: aString).! !!MusicalStream methodsFor: 'accessing' stamp: 'nm 5/24/2003 14:00'!addNoteNamed: aString octave: anIntegerself addNote: (MusicalNote new named: aString; octave: anInteger).! !!MusicalStream methodsFor: 'accessing' stamp: 'nm 5/18/2003 17:48'!addNotes: anArrayanArray do: [:each | self addNote: each]! !!MusicalStream methodsFor: 'accessing' stamp: 'nm 5/18/2003 17:47'!addNotesNamed: anArrayOfStringanArrayOfString do: [:each | self addNoteNamed: each]! !!MusicalStream methodsFor: 'accessing' stamp: 'nm 11/17/2002 17:57'!first^self notes first! !!MusicalStream methodsFor: 'accessing' stamp: 'nm 11/16/2002 21:00'!notes^notes! !!MusicalStream methodsFor: 'accessing' stamp: 'nm 5/18/2003 20:12'!notes: anOrderedCollection"no habr’a que usarlo. S—lo agregar por #addNote"notes_ anOrderedCollection! !!MusicalStream methodsFor: 'initialization' stamp: 'nm 11/16/2002 20:59'!initializenotes_ OrderedCollection new.! !!MusicalStream methodsFor: 'playing' stamp: 'nm 6/4/2003 19:43'!playself playOn: FMClarinetSound! !!MusicalStream methodsFor: 'playing' stamp: 'nm 12/22/2003 12:17'!playOn: anAbstractSoundself playOn: anAbstractSound! !!MusicalStream methodsFor: 'converting' stamp: 'nm 12/22/2003 15:20'!abstractNotes| newNotes |newNotes:= OrderedCollection new.notes do: [:each | newNotes add: (AbstractMusicalNote new named: each name)].^newNotes.! !!Chord methodsFor: 'initialization' stamp: 'nm 12/22/2003 11:43'!initializesuper initialize.root_ MusicalNote new.duration:=1. "Chords, as they are 'abstracts', has a default duration"! !!Chord methodsFor: 'transforming' stamp: 'nm 12/22/2003 12:21'!asMelody| mel |mel:= Melody new.notes do: [:each | each duration: self duration. mel addNote: each].^mel! !!Chord methodsFor: 'transforming' stamp: 'nm 7/31/2002 18:01'!closenotes last octaveDown.notes last > root ifTrue:[self sort] ifFalse: [notes last octaveUp]! !!Chord methodsFor: 'transforming' stamp: 'nm 12/22/2003 14:55'!copyFromRoot"crea un acorde como s’ mismo desde la raiz"| chord |chord:= self deepCopy.^chord fromRoot.! !!Chord methodsFor: 'transforming' stamp: 'nm 11/13/2002 19:25'!duplicateAt: anInteger| note |note_ MusicalNote new name: (self notes at: anInteger) name; octave: (self notes at: anInteger) octave.self notes add: note octaveUp! !!Chord methodsFor: 'transforming' stamp: 'nm 11/13/2002 17:43'!enharmonic^Chord new notes: (self notes do: [:each | each enharmonic])! !!Chord methodsFor: 'transforming' stamp: 'nm 11/13/2002 17:42'!enharmonizeself notes do: [:each | each enharmonize]! !!Chord methodsFor: 'transforming' stamp: 'nm 12/22/2003 14:50'!fromRoot"ordena el acorde con la fundamental en el bajo y el resto ordenado"| note |notes at: 1 put: root.(2 to: notes size) do: [:idx | note:= notes at: idx-1 . notes at: idx put: (note copy transposeTo: (structure at: idx-1))]! !!Chord methodsFor: 'transforming' stamp: 'nm 7/31/2002 17:51'!invert: anIntegeranInteger < notes size ifTrue:[(notes allButLast: (notes size - anInteger )) do:[:each | each octaveUp]. self sort.]! !!Chord methodsFor: 'transforming' stamp: 'nm 7/31/2002 17:53'!opennotes second octaveUp.notes_ (notes first asOrderedCollection), (notes allButFirst:2), (notes second asOrderedCollection).self sort.! !!Chord methodsFor: 'private' stamp: 'nm 7/31/2002 17:41'!addEleventhFrom: aScale with: intervals(intervals includesSubString: 'b11') ifTrue:[ self addNote: aScale notes fourth stepDown. self notes last octaveUp.^self].(intervals includesSubString: '#11') ifTrue:[ self addNote: aScale notes fourth stepUp. self notes last octaveUp.^self].(intervals includesSubString: '11' ) ifTrue: [self addNote: aScale notes fourth. self notes last octaveUp.^self].! !!Chord methodsFor: 'private' stamp: 'nm 8/1/2002 14:25'!addFifthFrom: aScale with: intervals(intervals includesSubString: 'b5') | (intervals includesSubString: 'dim') ifTrue:[ self addNote: aScale notes fifth stepDown. ^self].(intervals includesSubString: '#5') | (intervals includesSubString: 'aug') ifTrue:[ self addNote: aScale notes fifth stepUp. ^self].self addNote: aScale notes fifth.! !!Chord methodsFor: 'private' stamp: 'nm 8/1/2002 14:24'!addNinthFrom: aScale with: intervals(intervals includesSubString: 'b9') ifTrue:[ self addNote: aScale notes second stepDown. self notes last octaveUp.^self].(intervals includesSubString: '#9') ifTrue:[ self addNote: aScale notes second stepUp.self notes last octaveUp. ^self].(intervals includesSubString: '9' ) ifTrue: [self addNote: aScale notes second.self notes last octaveUp. ^self]. ! !!Chord methodsFor: 'private' stamp: 'nm 7/31/2002 17:36'!addSeventhFrom: aScale with: intervals(intervals includesSubString: '7+') | (intervals includesSubString: 'MAJ') ifTrue:[ self addNote: aScale notes seventh stepUp.^self].(intervals includesSubString: '7') ifTrue:[ self addNote: aScale notes seventh.^self].(intervals includesSubString: 'dim') ifTrue:[ self addNote: aScale notes seventh stepDown.^self].! !!Chord methodsFor: 'private' stamp: 'nm 8/1/2002 13:39'!addThirdFrom: aScale with: intervals(intervals includesSubString:'sus') ifFalse:[self addNote: aScale notes third] ifTrue:[self addNote: aScale notes fourth].! !!Chord methodsFor: 'private' stamp: 'nm 7/31/2002 17:41'!addThirdTeenthFrom: aScale with: intervals(intervals includesSubString: 'b13') ifTrue:[ self addNote: aScale notes sixth stepDown. self notes last octaveUp.^self].(intervals includesSubString: '#13') ifTrue:[ self addNote: aScale notes sixth stepUp. self notes last octaveUp.^self].(intervals includesSubString: '13' ) | (intervals includesSubString: '6' ) ifTrue: [self addNote: aScale notes sixth. self notes last octaveUp.^self]. ! !!Chord methodsFor: 'private' stamp: 'nm 6/3/2003 19:17'!constructFrom: aScale with: intervalStringintervals_ intervalString."Esto est‡ mal, (intervals no se asigna bien) pero hay que tocar el #extractNoteFrom"self addThirdFrom: aScale with: intervalString. self correctOctave.self addFifthFrom: aScale with: intervalString. self correctOctave.self addSeventhFrom: aScale with: intervalString. self correctOctave.self addNinthFrom: aScale with: intervalString. self correctOctave.self addEleventhFrom: aScale with: intervalString. self correctOctave.self addThirdTeenthFrom: aScale with: intervalString. self correctOctave.! !!Chord methodsFor: 'private' stamp: 'nm 8/1/2002 14:27'!correctOctave[(notes at: (notes size -1) ) > notes last] whileTrue: [notes last octaveUp].! !!Chord methodsFor: 'private' stamp: 'nm 7/19/2002 18:17'!extractAlternateBassFrom: aString| note pos |pos_ aString indexOf:$/.pos > 0 ifTrue: [ note_ self extractNoteFrom: (aString allButFirst: pos)].^note.! !!Chord methodsFor: 'private' stamp: 'nm 6/3/2003 20:11'!extractNoteFrom: aString^self class extractNoteFrom: aString! !!Chord methodsFor: 'private' stamp: 'nm 11/13/2002 17:52'!needEnharmonize^(self notes anySatisfy: [:each | each name='E#']) | (self notes anySatisfy: [:each | each name='Cb']) | (self notes anySatisfy: [:each | each name='Fb']) | (self notes anySatisfy: [:each | each name='B#']) | self hasDoubleAlteration! !!Chord methodsFor: 'parsing' stamp: 'nm 5/20/2003 19:26'!degree: aDegree from: aScaleself degree: aDegree from: aScale with:''! !!Chord methodsFor: 'parsing' stamp: 'nm 12/22/2003 14:45'!degree: aDegree from: aScale with: intervalsString| scale note |scale_ aScale copy.scale rotate: (aDegree romanNumber).note_ MusicalNote new named: (scale notes first name).notes add: note.root_ note.self constructFrom: scale with: intervalsString.structure:= self intervals copy.! !!Chord methodsFor: 'parsing' stamp: 'nm 12/22/2003 14:45'!parse: aString| note altbass scale |name_ aString.altbass_ self extractAlternateBassFrom: aString.altbass notNil ifTrue: [notes add: altbass octaveDown].note_ self extractNoteFrom: aString.notes add: note.self root: note.(aString includesSubString: 'm' ) ifTrue: [scale_ MusicalScale dorianFrom: note] ifFalse: [scale_ MusicalScale mixolydianFrom: note].self constructFrom: scale with: aString.structure:= self intervals copy.! !!Chord methodsFor: 'playing' stamp: 'nm 11/13/2002 12:54'!arpeggioself arpeggioOn: FMClarinetSound! !!Chord methodsFor: 'playing' stamp: 'nm 11/18/2002 10:23'!arpeggioOn: anAbstractSoundsuper playOn: anAbstractSound! !!Chord methodsFor: 'playing' stamp: 'nm 6/3/2003 19:33'!playAndWaitUntilDone(self prepareToPlayOn: FMClarinetSound loudness: 200) playAndWaitUntilDone.! !!Chord methodsFor: 'playing' stamp: 'nm 12/22/2003 12:22'!playArpeggioself asMelody play! !!Chord methodsFor: 'playing' stamp: 'nm 12/22/2003 12:23'!playArpeggioOn: anAbstractSoundself asMelody playOn: anAbstractSound! !!Chord methodsFor: 'playing' stamp: 'nm 6/3/2003 19:33'!playOn: anAbstractSound(self prepareToPlayOn: anAbstractSound loudness: 200) play.! !!Chord methodsFor: 'playing' stamp: 'nm 6/3/2003 19:34'!playOn: anAbstractSound loudness: anInteger(self prepareToPlayOn: anAbstractSound loudness: anInteger) play.! !!Chord methodsFor: 'playing' stamp: 'nm 11/20/2002 19:05'!playPattern: anArray repeat: anInteger(1 to: anInteger) do:[:x| (1 to: anArray size) do: [:idx | self setDuration: (anArray at:idx). self play]]! !!Chord methodsFor: 'playing' stamp: 'nm 8/9/2003 17:30'!prepareToPlayOn: anAbstractSound loudness: anInteger| m |m_ MixedSound new.self notes do: [:each | m add: (AbstractSound noteSequenceOn: anAbstractSound default from: (Array with: (each prepareToPlayDuration: self duration loudness: anInteger))) pan:0.0].^m! !!Chord methodsFor: 'accessing' stamp: 'nm 5/18/2003 20:49'!addNote: aNote"MOCO"(aNote isKindOf: AbstractMusicalNote) ifTrue:[ notes add: (MusicalNote new name: aNote name)] ifFalse: [super addNote: aNote]! !!Chord methodsFor: 'accessing' stamp: 'nm 8/9/2003 17:31'!duration^duration! !!Chord methodsFor: 'accessing' stamp: 'nm 8/9/2003 17:31'!duration: anIntegerduration:= anInteger"notes do:[:each | each duration: anInteger]"! !!Chord methodsFor: 'accessing' stamp: 'nm 6/3/2003 19:11'!intervals^intervals! !!Chord methodsFor: 'accessing' stamp: 'nm 11/14/2002 18:53'!name^name! !!Chord methodsFor: 'accessing' stamp: 'nm 11/14/2002 18:53'!name: aStringname_ aString! !!Chord methodsFor: 'accessing' stamp: 'nm 7/20/2002 13:05'!root^root! !!Chord methodsFor: 'accessing' stamp: 'nm 7/20/2002 13:05'!root: aMusicalNoteroot_ aMusicalNote! !!Chord methodsFor: 'accessing' stamp: 'nm 6/3/2003 19:18'!transposeTo: anIntervalself needEnharmonize ifTrue: [self enharmonize].super transposeTo: anInterval.self needEnharmonize ifTrue: [self enharmonize]."self name: self root name, self intervals NO ANDA"! !!Chord methodsFor: 'printing' stamp: 'nm 11/18/2002 15:42'!printNotes| s |s_ ''.self notes do: [:each | s_ s,each name,each octave asString,' '].^s! !!Chord methodsFor: 'printing' stamp: 'nm 7/20/2002 14:10'!printOn: aStreamaStream nextPutAll: 'root '; print: root; nextPutAll: ' '.notes do: [:each | each printOn: aStream].! !!Chord methodsFor: 'testing' stamp: 'nm 11/13/2002 17:33'!hasDoubleAlteration^self notes anySatisfy: [:each | each hasDoubleAlteration]! !!Chord methodsFor: 'testing' stamp: 'nm 12/22/2003 15:23'!hasNote: anAbstractMusicalNote^self abstractNotes includes: anAbstractMusicalNote! !!Chord methodsFor: 'testing' stamp: 'nm 12/22/2003 14:56'!isMajor^structure first isMajor! !!Chord methodsFor: 'testing' stamp: 'nm 12/22/2003 14:56'!isMinor^structure first isMinor! !!Melody methodsFor: 'rythmic transformation' stamp: 'nm 6/4/2003 16:49'!adaptToRhythm"assign each rhythm value to each note"(rhythm countNotes ~= self countNotes) ifTrue:[self error: 'Rhythmic and melodic notes are differents in size'] ifFalse:[self notes with: rhythm notes do:[:eachnote :eachrhythm | eachnote duration: eachrhythm]]! !!Melody methodsFor: 'rythmic transformation' stamp: 'nm 5/18/2003 19:32'!forceRhythmicPattern"No anda"| melidx| melidx:=1.(1 to: rhythm countNotes) do: [:idx | (notes at: idx) duration: (rhythm at:idx). (melidx < self countNotes) ifTrue:[melidx:=1. self addNote: (notes at: melidx) copy] ifFalse: [melidx:= melidx + 1]]! !!Melody methodsFor: 'rythmic transformation' stamp: 'nm 12/22/2003 13:07'!forceRhythmicPattern: aRhythm"No anda"| melidx| melidx:=1.(1 to: aRhythm countNotes) do: [:idx | self addNote:((notes atWrap: melidx) duration: (aRhythm at:idx) copy). melidx:= melidx + 1]! !!Melody methodsFor: 'melodic transformation' stamp: 'nm 6/5/2003 18:40'!mapContinumAndReturnAt: aSymbol from: startNote to: endNote until: aNumber"maps the range of notes, so they reaches aNumber in the middle and return to is original value"| middle return |middle:= startNote + (endNote - startNote) / 2 asInteger.return:= (maps at: aSymbol) at: endNote.self mapContinumAt: aSymbol from: startNote to: middle until: aNumber.self mapContinumAt: aSymbol from: middle + 1 to: endNote until: return.! !!Melody methodsFor: 'melodic transformation' stamp: 'nm 6/5/2003 18:04'!mapContinumAt: aSymbol from: startNote to: endNote ratio: aNumber"maps notes to a continum value, given by aNumber.""ej. crescendo aSymbol=#loudness ratio > 1. decrescendo ratio<1"| newRun lastArray map acu |map:= maps at: aSymbol.newRun:= map copyFrom:1 to: startNote-1.lastArray:= map copyFrom:endNote+1 to: map size.acu:= map at: startNote.(startNote to: endNote) do: [:idx| newRun:= newRun,(RunArray new:1 withAll: acu). acu:= acu * aNumber].maps at:aSymbol put: newRun,lastArray.! !!Melody methodsFor: 'melodic transformation' stamp: 'nm 6/5/2003 18:35'!mapContinumAt: aSymbol from: startNote to: endNote until: aNumber"maps notes to a continum value until reach aNumber.""ej. crescendo aSymbol=#loudness ratio > 1. decrescendo ratio<1"| newRun lastArray map acu delta |map:= maps at: aSymbol.newRun:= map copyFrom:1 to: startNote-1.lastArray:= map copyFrom:endNote+1 to: map size.acu:= map at: startNote.delta:= ((aNumber - acu) / (endNote - startNote )) asFloat.aNumber < acu ifTrue:[delta:= delta negated].(startNote to: endNote) do: [:idx| newRun:= newRun,(RunArray new:1 withAll: acu). acu:= acu + delta].maps at:aSymbol put: newRun,lastArray.! !!Melody methodsFor: 'melodic transformation' stamp: 'nm 5/18/2003 19:15'!pattern: aCollection repeat: anInteger| col |col_ OrderedCollection new.anInteger timesRepeat: [col addAll: aCollection].self addNotesNamed: col.! !!Melody methodsFor: 'initialization' stamp: 'nm 6/5/2003 13:37'!defaultMaps"set default values for default maps (instruments, articulation and loudness)"self mapAllAt: #instruments with: FMSound oboe1; mapAllAt: #articulation with:0; mapAllAt: #loudness with: 50.! !!Melody methodsFor: 'initialization' stamp: 'nm 6/5/2003 11:09'!initializesuper initialize.rhythm:= Rhythm new.maps_ Dictionary new! !!Melody methodsFor: 'inquiring' stamp: 'nm 5/18/2003 20:29'!doesNotUnderstand: aMessage"redirects message to rhythm. Two argument message not expected"(aMessage arguments size = 1) ifTrue: [^self rhythm perform: aMessage selector with: (aMessage arguments at:1) ] ifFalse: [^self rhythm perform: aMessage selector]! !!Melody methodsFor: 'inquiring' stamp: 'nm 6/5/2003 19:54'!firstNoteAtCurrentBar^notes at: (self rhythm firstNoteAtCurrentBar)! !!Melody methodsFor: 'accessing' stamp: 'nm 5/18/2003 20:16'!addNote: aMusicalNotesuper addNote: aMusicalNote.rhythm addNote: aMusicalNote duration! !!Melody methodsFor: 'accessing' stamp: 'nm 6/5/2003 10:56'!articulationMap^maps at: #articulation! !!Melody methodsFor: 'accessing' stamp: 'nm 6/5/2003 10:56'!instrumentMap^maps at: #instruments! !!Melody methodsFor: 'accessing' stamp: 'nm 6/5/2003 10:56'!loudnessMap^maps at: #loudness! !!Melody methodsFor: 'accessing' stamp: 'nm 5/18/2003 18:47'!rhythm^rhythm! !!Melody methodsFor: 'accessing' stamp: 'nm 6/4/2003 16:48'!rhythm: aRhythm"set rhythm and assign each rhythm value to each note"rhythm_ aRhythm.self adaptToRhythm.! !!Melody methodsFor: 'private' stamp: 'nm 6/5/2003 11:05'!initializeMapAt: aSymbol with: anObject| map |map_ RunArray new: (self countNotes) withAll: anObject. maps at: aSymbol put: map! !!Melody methodsFor: 'private' stamp: 'nm 6/5/2003 11:36'!mapAllAt: aSymbol with: anObject"maps all actual notes to a value "maps at: aSymbol ifAbsent:[^self initializeMapAt: aSymbol with: anObject].maps at: aSymbol put: (RunArray new:self countNotes withAll: anObject).! !!Melody methodsFor: 'private' stamp: 'nm 12/22/2003 13:14'!mapAt: aSymbol from: begin to: end with: anObject"maps range of notes to anObject "| newRun firstArray lastArray map |map:= maps at: aSymbol.firstArray:= map copyFrom:1 to: begin-1.lastArray:= map copyFrom:end+1 to: map size.newRun:= firstArray,(RunArray new:end - begin +1 withAll: anObject),lastArray.maps at: aSymbol put: newRun! !!Melody methodsFor: 'private' stamp: 'nm 6/5/2003 11:06'!mapUnmappedAt: aSymbol with: anObject"maps unmapped notes (from last mapping) to value anObject "| map |map:= maps at: aSymbol.map isNil ifTrue:[self initializeMapAt: aSymbol with: anObject ] ifFalse:[ map addLast: anObject times: (self countNotes - map size)]! !!Melody methodsFor: 'playing' stamp: 'nm 6/5/2003 19:34'!asMelody"implemented differently by MusicalScale class"^self! !!Melody methodsFor: 'playing' stamp: 'nm 10/22/2003 11:32'!playmaps isEmpty ifTrue:[self defaultMaps].(AbstractSound noteSequenceOn: self instrumentMap first from: self prepareToPlay) play! !!Melody methodsFor: 'playing' stamp: 'nm 6/5/2003 13:35'!play2"probando"| note articulation |(1 to: self countNotes) do: [:idx | note:= (notes at:idx). articulation:= self articulationMap at: idx. ((note isNotRest) or: [articulation > 0]) ifTrue:[note playOn: (self instrumentMap at: idx) duration: (note duration - articulation) loudness: (self loudnessMap at: idx)]. note isRest ifTrue: [ (AbstractSound dur: note duration abs) play]. (articulation>0) ifTrue: [(AbstractSound dur: articulation) play]].! !!Melody methodsFor: 'playing' stamp: 'nm 6/5/2003 12:18'!playAndWaitUntilDone(AbstractSound noteSequenceOn: FMSound default from: self prepareToPlay) playAndWaitUntilDone! !!Melody methodsFor: 'playing' stamp: 'nm 6/4/2003 16:15'!playOn: anAbstractSoundself playOn: anAbstractSound loudness: 100.! !!Melody methodsFor: 'playing' stamp: 'nm 6/5/2003 13:31'!playOn: anAbstractSound loudness: anInteger(AbstractSound noteSequenceOn: (self instrumentMap first) from: self prepareToPlay) play.! !!Melody methodsFor: 'playing' stamp: 'nm 6/5/2003 19:41'!playOnInstruments"Problema. No puede hacer polifon’a""Deber’a estar en Score? C—mo? "self instrumentMap withStartStopAndValueDo: [:start :stop :instrument |(AbstractSound noteSequenceOn: instrument from: (self prepareToPlayFrom: start to: stop)) playAndWaitUntilDone]! !!Melody methodsFor: 'playing' stamp: 'nm 6/5/2003 17:24'!prepareToPlay"anwser an array of notes for playing from the begining to end"^self prepareToPlayFrom:1 to: self countNotes! !!Melody methodsFor: 'playing' stamp: 'nm 6/5/2003 17:26'!prepareToPlayFrom: start to: stop" anwser an array of notes for playing from start note to stop note "|col note articulation |col_OrderedCollection new.(start to: stop) do: [:idx | note:= (notes at:idx). articulation:= self articulationMap at: idx. ((note isNotRest) or: [articulation > 0]) ifTrue:[ col add:(note prepareToPlayDuration: (note duration - articulation) loudness: (self loudnessMap at: idx))]. note isRest ifTrue: [col add: (note prepareToPlayRest)]. (articulation>0) ifTrue: [col add: (note prepareToPlayArticulation: articulation)]].^col! !!MusicalStream class methodsFor: 'testing' stamp: 'nm 5/18/2003 17:48'!test1" MusicalStream test1 play "" MusicalStream test1 octaveUp play "" MusicalStream test1 reverse play "" MusicalStream test1 invert play "" MusicalStream test1 reverseAndInvert play "" (MusicalStream test1 rotate: 2) play "" (MusicalStream test1 transposeTo:'5j') play ""A minimal melody, equal time"^(self new) addNotesNamed: #('C' 'D' 'E').! !!MusicalStream class methodsFor: 'testing' stamp: 'nm 5/18/2003 17:15'!test2" MusicalStream test2 play""A minimal melody with durations and octaves"^(self new) addNote: (MusicalNote new named: 'C'; duration: 1; octave:4); addNote: (MusicalNote new named: 'G'; duration: 0.5; octave: 3); addNote: (MusicalNote new named: 'C'; duration: 1.5; octave: 4).! !!MusicalStream class methodsFor: 'instance creation' stamp: 'nm 11/17/2002 17:39'!fromNote: aNote withIntervals: aCollectionOfIntervals| note musstream|note_ aNote copy.musstream_self new addNote: note.aCollectionOfIntervals collect:[:each | note_ note transposeTo: each. musstream addNote: note].^musstream.! !!MusicalStream class methodsFor: 'instance creation' stamp: 'nm 11/16/2002 20:59'!new^super new initialize! !!Chord class methodsFor: 'as yet unclassified' stamp: 'nm 6/3/2003 20:10'!extractNoteFrom: aString| note newnote |note_ MusicalNote new named: aString.newnote_ MusicalNote new.note firstIsValid ifFalse: [^nil] ifTrue: [newnote named: (aString first) asString].((aString size >1) and: [note secondIsValid]) ifTrue: [newnote add: (aString second)].((aString size >2) and: [note thirdIsValid] and: [(aString second) = (aString third)]) ifTrue: [newnote add: (aString third)].^newnote.! !!Chord class methodsFor: 'as yet unclassified' stamp: 'nm 6/4/2003 16:20'!test"Ejemplos de testeo crear escala mayor MusicalScale majorFromName: 'C'. (D# Bb etc)c_ Chord new parse: 'C7/9' c invert:1c openc close c fromRoote_ MusicalScale majorFromName:'C'c_ Chord new degree: 'II' from:e with:'7'Hacer print de estos ejemploss"! !!Melody class methodsFor: 'as yet unclassified' stamp: 'nm 5/18/2003 18:34'!test1"A simple melody, just like MusicalStream"" Melody test1 play "^(self new) addNotesNamed: #('C' 'D' 'E' 'F' 'G' 'F' 'E' 'D' 'C') ! !!Melody class methodsFor: 'as yet unclassified' stamp: 'nm 5/18/2003 18:35'!test2"A melody with an associated rhythmic pattern"" Melody test2 play "^(self test1) rhythm: (Rhythm test1); adaptToRhythm. ! !!Melody class methodsFor: 'as yet unclassified' stamp: 'nm 5/18/2003 20:30'!test3"A melody with stacatto"" Melody test3 play "| mel |mel:= self test2.mel tempoTo: 1/2; stacatto.^mel! !!Melody class methodsFor: 'as yet unclassified' stamp: 'nm 5/18/2003 19:16'!test4"A melody pattern"" Melody test4 play "^(self new) pattern: #('E' 'F' 'A' 'B') repeat: 5; tempoTo: 1/5! !!Melody class methodsFor: 'as yet unclassified' stamp: 'nm 5/18/2003 19:35'!test5"A melody and rhythmic pattern"" Melody test5 play "^(self test4) rhythm: (Rhythm new pattern: #(1 1 1 1.5) repeat:5); adaptToRhythm;tempoTo: 1/6! !!Melody class methodsFor: 'as yet unclassified' stamp: 'nm 12/22/2003 12:59'!test6" Melody test6 play NO ANDA "^(self new) addNotesNamed: #('E' 'F' 'A' 'B'); forceRhythmicPattern: (Rhythm new pattern: #(1 1 1 2) repeat:5); tempoTo: 1/2! !!Melody class methodsFor: 'as yet unclassified' stamp: 'nm 6/5/2003 12:18'!test7" Melody test7""A minimal melody with different articulations"| mel |mel:= (self new initialize).mel addNote: (MusicalNote new named: 'C'; duration: 0.3); addNote: (MusicalNote new named: 'D'; duration: 0.3); addNote: (MusicalNote new named: 'E'; duration: 0.3); addNote: (MusicalNote new named: 'F'; duration: 0.3); addNote: (MusicalNote new named: 'G'; duration: 0.6); defaultMaps.mel mapAllAt: #articulation with: 0.2; playAndWaitUntilDone; mapAllAt: #articulation with: 0.1; playAndWaitUntilDone; mapAllAt: #articulation with: 0; playAndWaitUntilDone! !!Melody class methodsFor: 'examples' stamp: 'nm 6/5/2003 18:57'!choralAltoBach1^(self new) initialize; addNotesNamed: #('G' 'G' 'E' 'E' 'E' 'D#' ); octaveUp; addNoteNamed: 'B' octave:3; rhythm: (Rhythm choralRhythmVoices)! !!Melody class methodsFor: 'examples' stamp: 'nm 6/4/2003 19:57'!choralAltoBach2^(self new) initialize; addNotesNamed: #('G' 'F#' 'E' 'D#' 'E' 'E' 'D#' ); octaveUp; addNoteNamed: 'B' octave:3; rhythm: (Rhythm new addNotes: #(1 1 0.5 0.5 1 1 1 2))! !!Melody class methodsFor: 'examples' stamp: 'nm 6/4/2003 16:49'!choralAltoJazz^(self new) addNotesNamed: #('G' 'G' 'E' 'E' 'D#' 'D' ); octaveUp; rhythm: (Rhythm choralRhythm)! !!Melody class methodsFor: 'examples' stamp: 'nm 6/4/2003 16:49'!choralAltoRoma^(self new) addNotesNamed: #('G' 'F' 'F' 'E' 'D#' 'E' ); octaveUp; rhythm: (Rhythm choralRhythm)! !!Melody class methodsFor: 'examples' stamp: 'nm 6/4/2003 16:49'!choralBajoBach1^(self new) addNoteNamed: 'E' octave: 3; addNoteNamed: 'G' octave: 3; addNoteNamed: 'C' octave: 3; addNoteNamed: 'E' octave: 3; addNoteNamed: 'A' octave: 2; addNoteNamed: 'B' octave: 2; addNoteNamed: 'E' octave: 3; rhythm: (Rhythm choralRhythmVoices)! !!Melody class methodsFor: 'examples' stamp: 'nm 6/4/2003 16:49'!choralBajoBach2^(self new) addNoteNamed: 'E' octave: 3; addNoteNamed: 'D' octave: 3; addNoteNamed: 'C' octave: 3; addNoteNamed: 'B' octave: 2; addNoteNamed: 'A' octave: 2; addNoteNamed: 'B' octave: 2; addNoteNamed: 'E' octave: 3; rhythm: (Rhythm new addNotes: #(1 1 1.5 0.5 1 1 2))! !!Melody class methodsFor: 'examples' stamp: 'nm 6/4/2003 16:49'!choralBajoJazz^(self new) addNoteNamed: 'E' octave: 3; addNoteNamed: 'A' octave: 2; addNoteNamed: 'F#' octave: 3; addNoteNamed: 'C' octave: 3; addNoteNamed: 'B' octave: 2; addNoteNamed: 'E' octave: 3; rhythm: (Rhythm choralRhythm)! !!Melody class methodsFor: 'examples' stamp: 'nm 6/4/2003 16:49'!choralBajoRoma^(self new) addNoteNamed: 'E' octave: 3; addNoteNamed: 'G#' octave: 3; addNoteNamed: 'A' octave: 3; addNoteNamed: 'B' octave: 3; addNoteNamed: 'B' octave: 2; addNoteNamed: 'A' octave: 2; rhythm: (Rhythm choralRhythm)! !!Melody class methodsFor: 'examples' stamp: 'nm 6/5/2003 18:58'!choralSoprano^(self new) initialize; addNotesNamed: #('B' 'B' 'A' 'G' 'F#' 'E'); octaveUp; rhythm: (Rhythm choralRhythm)! !!Melody class methodsFor: 'examples' stamp: 'nm 6/4/2003 16:50'!choralTenorBach1^(self new) addNotesNamed: #('E' 'D' 'C' ); octaveUp; addNoteNamed: 'B' octave: 3; addNoteNamed: 'C' octave: 4; addNoteNamed: 'B' octave: 3; addNoteNamed: 'G' octave: 3; rhythm: (Rhythm choralRhythmVoices)! !!Melody class methodsFor: 'examples' stamp: 'nm 6/4/2003 16:50'!choralTenorBach2^(self new) addNoteNamed: 'E' octave: 4; addNoteNamed: 'B' octave: 3; addNoteNamed: 'C' octave: 4; addNoteNamed: 'F#' octave: 3; addNoteNamed: 'G' octave: 3; addNoteNamed: 'C' octave: 4; addNoteNamed: 'B' octave: 3; addNoteNamed: 'A' octave: 3; addNoteNamed: 'G' octave: 3; rhythm: (Rhythm new addNotes: #(1 1 0.5 0.5 1 1 0.5 0.5 2))! !!Melody class methodsFor: 'examples' stamp: 'nm 6/4/2003 16:50'!choralTenorJazz^(self new) addNoteNamed: 'B' octave: 3; addNoteNamed: 'C' octave: 4; addNoteNamed: 'C#' octave: 4; addNoteNamed: 'B' octave: 3; addNoteNamed: 'C#' octave: 4; addNoteNamed: 'B' octave: 3; rhythm: (Rhythm choralRhythm)! !!Melody class methodsFor: 'examples' stamp: 'nm 6/4/2003 16:50'!choralTenorRoma^(self new) addNoteNamed: 'B' octave: 3; addNoteNamed: 'C' octave: 4; addNoteNamed: 'C#' octave: 4; addNoteNamed: 'B' octave: 3; addNoteNamed: 'C' octave: 4; addNoteNamed: 'C' octave: 4; rhythm: (Rhythm choralRhythm)! !!PaintMusicMorph methodsFor: 'private' stamp: 'nm 5/26/2003 15:31'!sortedMorphs| col |col:= SortedCollection new sortBlock: [:x :y | x left <= y left].self submorphs do: [:each | col add: each].^col.! !!PaintMusicMorph methodsFor: 'playing' stamp: 'nm 5/26/2003 15:52'!morphPlay: aMorph"NM. Falta hacer algo con el color y el alto""la respuesta es lineal y deber’a ser logaritmica. Tambien con escalas"(FMSound pitch: (((1 / aMorph top)*10000) + 100 asInteger) dur: (aMorph width /60) loudness: 100) play! !!PaintMusicMorph methodsFor: 'playing' stamp: 'nm 5/26/2003 16:01'!play"falta ejecutar en tiempo segśn valor de X""self sortedMorphs do:[:each | self morphPlay: each]""morphs:= self sortedMorphs.morphIdx:=1.(self left to: self width) do: [:x | x < (morphs at:morphIdx) left ifTrue:[(RestSound dur: (1 / 60) asFloat) playAndWaitUntilDone."" (RestSound dur: (aMorph left / 60) asFloat) playAndWaitUntilDone."! !!PaintMusicMorph methodsFor: 'initialization' stamp: 'nm 5/21/2003 14:22'!changedsuper changed! !!PaintMusicMorph methodsFor: 'initialization' stamp: 'nm 5/21/2003 15:02'!initializesuper initialize.self color: Color white! !!PreArmonizer methodsFor: 'processing' stamp: 'nm 12/22/2003 15:32'!preArmonize"returns a collection of candidate chords for each note on the melody"| candidates |candidates:= OrderedCollection new.melody notes do: [:each | candidates add: (tonality chordsForNote: each)].^candidates! !!PreArmonizer methodsFor: 'accessing' stamp: 'nm 12/22/2003 14:58'!melody: aMelodymelody:= aMelody! !!PreArmonizer methodsFor: 'accessing' stamp: 'nm 12/22/2003 14:58'!tonality: aTonalitytonality:= aTonality! !!Rhythm methodsFor: 'inquiring' stamp: 'nm 5/17/2003 20:15'!countBars^bars size! !!Rhythm methodsFor: 'inquiring' stamp: 'nm 5/17/2003 17:10'!countNotes^notes size! !!Rhythm methodsFor: 'inquiring' stamp: 'nm 5/17/2003 21:58'!currentBarDuration| fromNote toNote duration |fromNote:= self firstNoteAtCurrentBar.toNote:= self countNotes.duration:=0.(fromNote to: toNote) do: [:each | duration:= duration + notes at: each].^duration! !!Rhythm methodsFor: 'inquiring' stamp: 'nm 5/17/2003 20:34'!currentMeasure^measureMap at: (self countNotes).! !!Rhythm methodsFor: 'inquiring' stamp: 'nm 5/17/2003 20:36'!currentTempo^tempoMap at: (self countNotes).! !!Rhythm methodsFor: 'inquiring' stamp: 'nm 5/17/2003 20:29'!durationAtBar: anInteger! !!Rhythm methodsFor: 'inquiring' stamp: 'nm 5/17/2003 21:58'!firstNoteAtCurrentBar^bars at: (self countBars)! !!Rhythm methodsFor: 'inquiring' stamp: 'nm 5/17/2003 20:07'!measureAtNote: anInteger^measureMap at: anInteger! !!Rhythm methodsFor: 'inquiring' stamp: 'nm 5/17/2003 20:07'!tempoAtNote: anInteger^tempoMap at: anInteger! !!Rhythm methodsFor: 'playing' stamp: 'nm 5/17/2003 14:17'!playself playOn: FMClarinetSound."SampledSound useCoffeeCupClink (no sirve, porque tiene un eco que confunde. Necesito otro sonido percusivo"! !!Rhythm methodsFor: 'playing' stamp: 'nm 5/17/2003 13:52'!playOn: anAbstractSound| col |col_OrderedCollection new.self notes do: [:each | each negative ifFalse:[col add: (Array with: 'a4' with: each with: 300)] ifTrue:[col add: (Array with: #rest with:each abs ) ]]. (AbstractSound noteSequenceOn: anAbstractSound default from: col) play.^col! !!Rhythm methodsFor: 'initialization' stamp: 'nm 5/17/2003 21:43'!initializenotes_ OrderedCollection new.bars_ OrderedCollection with:1.tempo:= Tempo new:60.measure:= Measure new: '4/4'! !!Rhythm methodsFor: 'printing' stamp: 'nm 5/17/2003 12:44'!printOn: aStreamself notes do: [:each | aStream nextPutAll: (each asString),' '].! !!Rhythm methodsFor: 'adding' stamp: 'nm 5/17/2003 21:40'!addNote: aNumberself notes add: aNumber.self mapMeasure.self mapTempo.self updateBars.! !!Rhythm methodsFor: 'adding' stamp: 'nm 5/17/2003 20:01'!addNotes: aCollectionaCollection do:[:each | self addNote: each]! !!Rhythm methodsFor: 'accessing' stamp: 'nm 5/18/2003 19:20'!at: anInteger^notes at: anInteger! !!Rhythm methodsFor: 'accessing' stamp: 'nm 5/17/2003 15:13'!measure^measure! !!Rhythm methodsFor: 'accessing' stamp: 'nm 5/17/2003 15:32'!measure: aMeasureaMeasure isString ifTrue:[measure:= Measure new: aMeasure] ifFalse:[measure:= aMeasure]! !!Rhythm methodsFor: 'accessing' stamp: 'nm 5/17/2003 15:26'!measureMap^measureMap! !!Rhythm methodsFor: 'accessing' stamp: 'nm 11/18/2002 16:58'!notes^notes! !!Rhythm methodsFor: 'accessing' stamp: 'nm 5/17/2003 13:19'!notes: anOrderedCollectionnotes_ anOrderedCollection.! !!Rhythm methodsFor: 'accessing' stamp: 'nm 11/18/2002 16:57'!tempo^tempo! !!Rhythm methodsFor: 'accessing' stamp: 'nm 5/17/2003 15:32'!tempo: aTempoaTempo isInteger ifTrue: [tempo:= Tempo new: aTempo] ifFalse: [tempo_ aTempo].tempo addDependent: self.! !!Rhythm methodsFor: 'accessing' stamp: 'nm 5/17/2003 16:33'!tempoMap^tempoMap! !!Rhythm methodsFor: 'private' stamp: 'nm 5/17/2003 21:33'!addBar: anIntegerbars add: anInteger.! !!Rhythm methodsFor: 'private' stamp: 'nm 6/4/2003 16:52'!mapMeasure"maps notes to actual measure"measureMap isNil ifTrue:[ measureMap_ RunArray new: (self countNotes) withAll: measure ] ifFalse:[ measureMap addLast: measure times: (self countNotes - measureMap size)]! !!Rhythm methodsFor: 'private' stamp: 'nm 5/17/2003 22:08'!mapTempo"maps all notes to actual tempo"tempoMap isNil ifTrue:[ tempoMap_ RunArray new: (self countNotes) withAll: tempo ] ifFalse:[ tempoMap addLast: tempo times: (self countNotes - tempoMap size)]! !!Rhythm methodsFor: 'private' stamp: 'nm 5/17/2003 22:19'!updateBars| measureDuration |measureDuration:= self currentMeasure durationForTempo: (self currentTempo).(self currentBarDuration > measureDuration) ifTrue: [self addBar: self countNotes. (notes last > measureDuration) ifTrue:[(2 to: (notes last / measureDuration) ceiling) do:[:idx | self addBar:self countNotes]]]! !!Rhythm methodsFor: 'private' stamp: 'nm 5/17/2003 14:02'!updateDurationAt: anInteger with: newTempo"update note at anInteger according to newTempo"self notes at:anInteger put: ((self notes at:anInteger) * newTempo)! !!Rhythm methodsFor: 'modifying' stamp: 'nm 5/17/2003 16:57'!changeMeasure: aMeasuremeasure:= Measure new: aMeasure.! !!Rhythm methodsFor: 'modifying' stamp: 'nm 5/17/2003 16:42'!changeTempo: aTempotempo:= Tempo new: aTempo.! !!Rhythm methodsFor: 'modifying' stamp: 'nm 5/17/2003 17:17'!pattern: aCollection repeat: anInteger| col |col_ OrderedCollection new.anInteger timesRepeat: [col addAll: aCollection].self addNotes: col.! !!Rhythm methodsFor: 'modifying' stamp: 'nm 5/17/2003 16:55'!resetDurationstempoMap withStartStopAndValueDo: [:eachstart :eachstop :eachTempo | (eachstart to: eachstop) do: [:idx | self updateDurationAt: idx with: eachTempo realDuration]]! !!Rhythm methodsFor: 'updating' stamp: 'nm 5/17/2003 14:01'!update: newTempo"updates all notes according to newTempo"(1 to: notes size) do: [:idx| self updateDurationAt:idx with: newTempo].! !!Rhythm class methodsFor: 'instance creation' stamp: 'nm 11/18/2002 16:57'!new^super new initialize! !!Rhythm class methodsFor: 'instance creation' stamp: 'nm 11/29/2002 18:16'!newTempo: aTempo^(super new tempo: aTempo) initialize! !!Rhythm class methodsFor: 'instance creation' stamp: 'nm 5/18/2003 18:44'!test1"Creates a four measure single pattern""Rhythm test1 play"| tempo |tempo_ Tempo new:60.^(self newTempo:tempo) measure: (Measure new: '3/8'); pattern: #(1 0.5) repeat: 4; addNote: 1.5. "to finish with a long note"! !!Rhythm class methodsFor: 'instance creation' stamp: 'nm 5/18/2003 19:02'!test2"Change the tempo to double. NO se porque dej— de andar. Revisar tempoMap""Rhythm test2 play"| rhythm |rhythm:= self test1.rhythm tempo value: 120.^rhythm! !!Rhythm class methodsFor: 'instance creation' stamp: 'nm 5/18/2003 18:45'!test3"First two bars with original tempo, next with double tempo""Rhythm test3 play"^(self newTempo: 60) pattern: #(1 0.5) repeat: 2; changeTempo: 120; pattern: #(1 0.5) repeat: 2; addNote: 1.5; "to finish with a long note" resetDurations.! !!Rhythm class methodsFor: 'instance creation' stamp: 'nm 5/18/2003 18:45'!test4"Creates a four measure rhythm,first two in 3/4, next in 2/4""Rhythm test4 "^(self newTempo: 60) measure: '3/8'; pattern: #(1 0.5) repeat: 2; changeMeasure: '2/4'; pattern: #(1 0.5 0.5) repeat: 2; addNote: 4.5 . "to finish with a long note (two bars)"! !!Rhythm class methodsFor: 'samples' stamp: 'nm 5/24/2003 12:50'!choralRhythm^self new addNotes: #(1 1 1 1 2 2)! !!Rhythm class methodsFor: 'samples' stamp: 'nm 5/24/2003 13:55'!choralRhythmVoices^self new addNotes: #(1 1 1 1 1 1 2)! !!RhythmC methodsFor: 'accessing' stamp: 'nm 5/17/2003 12:43'!articulationMap: anRunArrayarticulationMap_ anRunArray! !!RhythmC methodsFor: 'accessing' stamp: 'nm 5/17/2003 13:51'!notes: anOrderedCollectionnotes_ anOrderedCollection.durations_ OrderedCollection new.(notes size) timesRepeat: [durations add: (ArticulatedNote new)].self update: tempo realDuration.self mapArticulation.! !!RhythmC methodsFor: 'private' stamp: 'nm 5/17/2003 12:43'!articulateAt: anInteger with: aNumber(self durationAt: anInteger) sound:(self soundDurationAt:anInteger) rest:aNumber.! !!RhythmC methodsFor: 'modifying' stamp: 'nm 5/17/2003 12:43'!mapArticulationarticulationMap withStartStopAndValueDo: [:eachstart :eachstop :eachvalue | (eachstart to: eachstop) do: [:idx | ((self durationAt:idx) isRest) ifFalse: [self articulateAt: idx with: eachvalue]]].! !!RhythmC class methodsFor: 'instance creation' stamp: 'nm 5/17/2003 12:43'!new^super new initialize! !!RhythmC class methodsFor: 'instance creation' stamp: 'nm 5/17/2003 12:43'!newTempo: aTempo^(super new tempo: aTempo) initialize! !!RhythmC class methodsFor: 'instance creation' stamp: 'nm 5/17/2003 12:43'!test! !!Score methodsFor: 'initialization' stamp: 'nm 6/4/2003 16:36'!initializevoices_ OrderedCollection new! !!Score methodsFor: 'playing' stamp: 'nm 6/4/2003 16:38'!playvoices do: [:each | each play]! !!Score methodsFor: 'playing' stamp: 'nm 6/4/2003 16:38'!playOn: anAbstractSoundvoices do: [:each | each playOn: anAbstractSound]! !!Score methodsFor: 'accessing' stamp: 'nm 6/4/2003 16:37'!addVoice: aMelodyvoices add: aMelody! !!Score methodsFor: 'accessing' stamp: 'nm 6/4/2003 16:37'!removeVoice: aMelodyvoices remove: aMelody! !!Score methodsFor: 'accessing' stamp: 'nm 6/4/2003 16:36'!voices^voices! !!Score methodsFor: 'accessing' stamp: 'nm 6/4/2003 16:36'!voices: aCollectionvoices:=aCollection! !!Score methodsFor: 'inquiring' stamp: 'nm 6/5/2003 19:52'!countBars"answer number of bars. assume there are no staff with different time signature"^voices first countBars! !!Score class methodsFor: 'as yet unclassified' stamp: 'nm 6/4/2003 16:36'!new^super new initialize! !!Score class methodsFor: 'examples' stamp: 'nm 6/5/2003 18:56'!choralBach1^(self new) initialize; addVoice: Melody choralSoprano; addVoice: Melody choralAltoBach1; addVoice: Melody choralTenorBach1; addVoice: Melody choralBajoBach1! !!Score class methodsFor: 'examples' stamp: 'nm 1/20/2004 14:47'!choralBach2^(self new) initialize; addVoice: Melody choralSoprano; addVoice: Melody choralAltoBach2; addVoice: Melody choralTenorBach2; addVoice: Melody choralBajoBach2! !!Score class methodsFor: 'examples' stamp: 'nm 1/20/2004 14:47'!choralJazz^(self new) initialize; addVoice: Melody choralSoprano; addVoice: Melody choralAltoJazz; addVoice: Melody choralTenorJazz; addVoice: Melody choralBajoJazz! !!Score class methodsFor: 'examples' stamp: 'nm 1/20/2004 14:47'!choralRoma^(self new) initialize; addVoice: Melody choralSoprano; addVoice: Melody choralAltoRoma; addVoice: Melody choralTenorRoma; addVoice: Melody choralBajoRoma! !!Tempo methodsFor: 'accessing' stamp: 'nm 11/29/2002 13:25'!realDuration^ (60 / self value) asFloat! !!Tempo methodsFor: 'accessing' stamp: 'nm 11/17/2002 18:21'!value^ value! !!Tempo methodsFor: 'accessing' stamp: 'nm 11/29/2002 13:22'!value: anIntegervalue_ anInteger.self changed: self realDuration.! !!Tempo methodsFor: 'printing' stamp: 'nm 11/29/2002 13:25'!printOn: aStreamaStream nextPutAll: ' value: ',self value asString; nextPutAll:' real duration: ', self realDuration asString.! !!Tempo class methodsFor: 'as yet unclassified' stamp: 'nm 11/29/2002 12:32'!newself shouldNotImplement! !!Tempo class methodsFor: 'as yet unclassified' stamp: 'nm 11/29/2002 12:36'!new: anInteger^super new value: anInteger.! !!Tonality methodsFor: 'processing' stamp: 'nm 12/22/2003 15:28'!chordsForNote: aMusicalNote"returns a collection of candidate chords for this note "^self allChords select: [:each | each hasNote: aMusicalNote].! !!Tonality methodsFor: 'tonalFunctions' stamp: 'nm 12/22/2003 15:25'!allChords^(OrderedCollection new) addAll: self tonicChords, self dominantChords, self subdominantChords; yourself! !!Tonality methodsFor: 'tonalFunctions' stamp: 'nm 12/22/2003 13:30'!dominantChord^Chord new degree: 'V' from: scale! !!Tonality methodsFor: 'tonalFunctions' stamp: 'nm 12/22/2003 13:30'!dominantChords^(OrderedCollection new) add: self dominantChord; add: (Chord new degree:'VII' from: scale); yourself! !!Tonality methodsFor: 'tonalFunctions' stamp: 'nm 12/22/2003 13:30'!subdominantChord^Chord new degree: 'IV' from: scale! !!Tonality methodsFor: 'tonalFunctions' stamp: 'nm 12/22/2003 13:31'!subdominantChords^(OrderedCollection new) add: self subdominantChord; add: (Chord new degree:'II' from: scale); yourself! !!Tonality methodsFor: 'tonalFunctions' stamp: 'nm 12/22/2003 13:27'!tonicChord^Chord new degree: 'I' from: scale! !!Tonality methodsFor: 'tonalFunctions' stamp: 'nm 12/22/2003 13:29'!tonicChords^(OrderedCollection new) add: self tonicChord; add: (Chord new degree:'VI' from: scale); add:(Chord new degree: 'III' from: scale); yourself! !!Tonality methodsFor: 'accessing' stamp: 'nm 12/22/2003 13:22'!mode: aSymbolmode:= aSymbol! !!Tonality methodsFor: 'accessing' stamp: 'nm 12/22/2003 13:22'!root: aMusicalNoteroot:=aMusicalNote! !!Tonality methodsFor: 'accessing' stamp: 'nm 12/22/2003 15:03'!scale^scale! !!Tonality methodsFor: 'accessing' stamp: 'nm 12/22/2003 13:27'!scale: aMusicalScalescale:= aMusicalScale! !!Tonality class methodsFor: 'as yet unclassified' stamp: 'nm 12/22/2003 13:27'!majorFromName: aString^(super new) mode: #major; root: (MusicalNote new named: aString); scale: (MusicalScale majorFromName: aString).! !!Tonality class methodsFor: 'as yet unclassified' stamp: 'nm 12/22/2003 13:32'!minorFromName: aString^(super new) mode: #minor; root: (MusicalNote new named: aString); scale: (MusicalScale harmonicMinorFromName: aString).! !!Tonality class methodsFor: 'as yet unclassified' stamp: 'nm 12/22/2003 13:25'!new^self shouldNotImplement! !MusicalNote removeSelector: #askCanPlay!MusicalInterval initialize!ChordPlayerMorph removeSelector: #changeScale!ChordPlayerMorph removeSelector: #initializeScales!ChordPlayerMorph removeSelector: #makeScaleButton!ChordPlayerMorph removeSelector: #scale!ChordPlayerMorph removeSelector: #setColorForDegree:!ChordPlayerMorph removeSelector: #withChordPalette!ChordPaletteMorph removeSelector: #chordFromName:scale:!ChordMorph removeSelector: #initializeName:!AbstractSound initialize!AbstractMusicalNote initialize!