# Praat script simul_dbm_diphthongs.praat # Angelica van Beemdelust 06-06-2020 # Based on script used in Boersma, Paul. 2019. Simulated distributional learning in deep Boltzmann machines leads to the emergence of discrete categories. ICPhS. 1520-1524. form Emergence of three vowels word Foreground_colour Yellow word Background_colour Maroon word Button_colour Olive word Font Times natural Font_size 35 boolean Include_sound 1 boolean Include_meaning 1 choice Language: 1 button All meanings language button Short vowel language button Random gap language button Fixed gap language button a-less language button u-less language endform demo.foregroundColour$ = foreground_colour$ demo.backgroundColour$ = background_colour$ demo.buttonColour$ = button_colour$ demo.font$ = font$ demo.fontSize = font_size @sound procedure sound vowels$ = "aeiou" numberOfVowels = length (vowels$) f1_erb# = { 13, 10, 7, 10, 7 } f2_erb# = { 19, 22, 25, 16, 13 } ambientStdev_erb = 1.0 auditorySpreading_erb = 0.68 numberOfAuditoryNodes = 60 numberOfAuditoryNodesPerSlab = 30 fmin_erb = 4.0 fmax_erb = 28.0 erbsPerNode = (fmax_erb - fmin_erb) / (numberOfAuditoryNodesPerSlab - 1) auditorySpreading_nodes = auditorySpreading_erb / erbsPerNode endproc if language$ = "Fixed gap language" # create some sort of form within the script to let the user determine which diphthongs to leave out. beginPause: "Which meaning(s) do you want to remove?" comment: "Any pair combinations of [aeiou], space for separation e.g. 'ea eo iu ue uo'" sentence: "fixed gap", "ea eo iu ue uo" clicked = endPause: "submit", 1 writeInfoLine: "Gap(s) in this language: " appendInfoLine: fixed_gap$ @split (" ", fixed_gap$) numberOfRemovedMeanings = split.length endif # this procedure is used to split up the sentence input from the user and determine which gaps are desired. procedure split (sep$, str$) # sep$ = separator (i.e. " ") # str$ = string to separate # sepLength = separator length sepLength = length(sep$) .length = 0 repeat stringLength = length(str$) sep = index(str$, sep$) if sep > 0 part$ = left$(str$, sep-1) str$ = mid$(str$, sep+sepLength, stringLength) else part$ = str$ endif .length = .length+1 array$[.length] = part$ until sep = 0 endproc #setting up language generator vowels1$ = "aeiou" vowels2$ = "aeiou" all_vowels$ = "aeiou" #beginning language generator procedure create_Meaning: vowels1$, vowels2$ # k is the true index of the meaning k = 0 # magic string for short vowels if vowels1$ = "short" numberOfVowels1 = length (all_vowels$) numberOfVowels2 = length (all_vowels$) for i to numberOfVowels2 for j to numberOfVowels1 if i <> j k += 1 v1$ = mid$ (all_vowels$, i) v2$ = mid$ (all_vowels$, j) meaning.morpheme$ [k] = "‘" + v2$ + v1$ + "’" endif endfor endfor # magic string for random gap language # l is the total number of indices of a complete language elif vowels1$ = "gap" numberOfVowels1 = length (all_vowels$) numberOfVowels2 = length (all_vowels$) l = 1 writeInfoLine: "Gaps in this language:" for i to numberOfVowels2 for j to numberOfVowels1 # initializing a variable be check if meaning is to be added meaningNotRemoved = 1 for number to size (removed#) # validity check for removal of meaning if l = removed# [number] meaningNotRemoved = meaningNotRemoved * 0 else meaningNotRemoved = meaningNotRemoved * 1 endif endfor v1$ = mid$ (all_vowels$, i) v2$ = mid$ (all_vowels$, j) if meaningNotRemoved k += 1 meaning.morpheme$ [k] = "‘" + v2$ + v1$ + "’" else gap$ = "‘" + v2$ + v1$ + "’" appendInfo: gap$ + ", " endif l += 1 endfor endfor # magic string for fixed gap based on user input language elif vowels1$ = "fixed gap" numberOfVowels1 = length (all_vowels$) numberOfVowels2 = length (all_vowels$) l = 1 for i to numberOfVowels2 for j to numberOfVowels1 v1$ = mid$ (all_vowels$, i) v2$ = mid$ (all_vowels$, j) meaningNotRemoved = 1 for removedMeaning to numberOfRemovedMeanings if array$[removedMeaning] = v2$ + v1$ meaningNotRemoved = meaningNotRemoved * 0 else meaningNotRemoved = meaningNotRemoved * 1 endif endfor if meaningNotRemoved k += 1 meaning.morpheme$ [k] = "‘" + v2$ + v1$ + "’" endif l += 1 endfor endfor else numberOfVowels1 = length (vowels1$) numberOfVowels2 = length (vowels2$) l = 1 for i to numberOfVowels2 for j to numberOfVowels1 k += 1 v1$ = mid$ (vowels1$, i) v2$ = mid$ (vowels2$, j) meaning.morpheme$ [k] = "‘" + v2$ + v1$ + "’" endfor endfor endif meaning.numberOfWords = k endproc if language$ = "All meanings language" # already set above. elsif language$ = "Short vowel language" vowels1$ = "short" elsif language$ = "a-less language" vowels1$ = "eiou" vowels2$ = "eiou" elsif language$ = "u-less language" vowels1$ = "aeio" vowels2$ = "aeio" elsif language$ = "Random gap language" vowels1$ = "gap" x = 0 removed# = zero# (5) #set an array of random numbers to randomize which gaps are in the language... ...These are indices to be removed from a language that contains all meaning, thus creating a new language... ... so here 5 random meanings are removed from all possible meanings. while x <= 4 n = randomInteger(1,25) n_valid = 1 #forloop guarantees different numbers in array, thus 5 removed meanings for number to size (removed#) if n <> removed# [number] n_valid = n_valid * 1 else n_valid = n_valid * 0 endif endfor if n_valid x += 1 removed# [x] = n endif endwhile elsif language$ = "Fixed gap language" vowels1$ = "fixed gap" endif @create_Meaning: vowels1$, vowels2$ #end of language generator numberOfInputNodes = include_sound * numberOfAuditoryNodes + include_meaning * meaning.numberOfWords numberOfMiddleNodes = 50 numberOfTopNodes = 20 learningRate = 0.001 semf.offsetNode = include_sound * numberOfAuditoryNodes label NETWORK step = 0 halfwayClickedTwoFormantsSlab1 = 0 halfwayClickedTwoFormantsSlab2 = 0 firstVowel = 1 firstMeaningVowel = 1 procedure learn: .learningRate @spreadUp: 1 @hebbianLearning: .learningRate @resonate: 1 @hebbianLearning: - .learningRate endproc procedure spreadUp: .stochastic activity3# = zero# (numberOfTopNodes) ; or to random values .numberOfMeanFieldEchoes = 10 for .iecho to .numberOfMeanFieldEchoes activity2# = sigmoid# (mul# (activity1#, weight12##) + mul# (weight23##, activity3#) + bias2#) if .stochastic activity2# = randomBernoulli# (activity2#) endif activity3# = sigmoid# (mul# (activity2#, weight23##) + bias3#) if .stochastic activity3# = randomBernoulli# (activity3#) endif endfor endproc procedure resonate: .stochastic .numberOfGibbsEchoes = 10 for .iecho to .numberOfGibbsEchoes activity1# = mul# (weight12##, activity2#) + bias1# activity3# = sigmoid# (mul# (activity2#, weight23##) + bias3#) if .stochastic activity3# = randomBernoulli# (activity3#) endif activity2# = sigmoid# (mul# (activity1#, weight12##) + mul# (weight23##, activity3#) + bias2#) if .stochastic activity2# = randomBernoulli# (activity2#) endif endfor endproc procedure hebbianLearning: .learningRate bias1# += .learningRate * activity1# bias2# += .learningRate * activity2# bias3# += .learningRate * activity3# weight12## += .learningRate * outer## (activity1#, activity2#) weight23## += .learningRate * outer## (activity2#, activity3#) endproc # # Create history. # soundDistribution = Create Matrix: "soundDistribution", ... 0.5, numberOfAuditoryNodes + 0.5, numberOfAuditoryNodes, 1.0, 1.0, 1, 1, 1, 1, 1, ~ 0.0 # # First level. # activity1# = zero# (numberOfInputNodes) bias1# = zero# (numberOfInputNodes) x1# = linear# (0, 100, numberOfInputNodes, 1) y1 = 42 # # First layer. # weight12## = zero## (numberOfInputNodes, numberOfMiddleNodes) # # Second level. # activity2# = zero# (numberOfMiddleNodes) bias2# = zero# (numberOfMiddleNodes) x2# = linear# (0, 100, numberOfMiddleNodes, 1) y2 = 66 # # Second layer. # weight23## = zero## (numberOfMiddleNodes, numberOfTopNodes) # # Third level. # activity3# = zero# (numberOfTopNodes) bias3# = zero# (numberOfTopNodes) x3# = linear# (0, 100, numberOfTopNodes, 1) y3 = 90 repeat @demo.erase if include_sound and include_meaning @demo.centredTitle: "Emergence of categories from sound–meaning pairs" elsif include_sound @demo.centredTitle: "Emergence of categories from sound alone" elsif include_meaning @demo.centredTitle: "Emergence of categories from meaning alone" endif # # Draw network area. # demo Select inner viewport: 20, 80, 20, 80 demo Axes: 0, 100, 0, 100 demo Paint rectangle: "silver", 0, 100, 0, 100 for i to numberOfInputNodes for j to numberOfMiddleNodes weight = weight12## [i, j] if weight > 0 demo Black demo Line width: weight demo Draw line: x1# [i], y1, x2# [j], y2 elsif weight < 0 demo White demo Line width: abs (weight) demo Draw line: x1# [i], y1, x2# [j], y2 endif endfor endfor for i to numberOfMiddleNodes for j to numberOfTopNodes weight = weight23## [i, j] if weight > 0 demo Black demo Line width: weight demo Draw line: x2# [i], y2, x3# [j], y3 elsif weight < 0 demo White demo Line width: abs (weight) demo Draw line: x2# [i], y2, x3# [j], y3 endif endfor endfor demo Black boundaryBetweenAuditoryAndSemanticPart = semf.offsetNode / numberOfInputNodes * 100 if include_sound demo Text special: 0, "left", 30, "bottom", demo.font$, demo.fontSize/2.0, "0", "[" demo Text special: 0.025 * boundaryBetweenAuditoryAndSemanticPart, "centre", 30, "bottom", demo.font$, demo.fontSize/2.0, "0", "5" demo Text special: 0.125 * boundaryBetweenAuditoryAndSemanticPart, "centre", 30, "bottom", demo.font$, demo.fontSize/2.0, "0", "10" demo Text special: 0.225 * boundaryBetweenAuditoryAndSemanticPart, "centre", 30, "bottom", demo.font$, demo.fontSize/2.0, "0", "15" demo Text special: 0.325 * boundaryBetweenAuditoryAndSemanticPart, "centre", 30, "bottom", demo.font$, demo.fontSize/2.0, "0", "20" demo Text special: 0.425 * boundaryBetweenAuditoryAndSemanticPart, "centre", 30, "bottom", demo.font$, demo.fontSize/2.0, "0", "25" demo Text special: 0.470 * boundaryBetweenAuditoryAndSemanticPart, "centre", 30, "bottom", demo.font$, demo.fontSize/2.0, "0", "]" demo Text special: 0.475 * boundaryBetweenAuditoryAndSemanticPart, "centre", 30, "bottom", demo.font$, demo.fontSize/2.0, "0", "[" demo Text special: 0.525 * boundaryBetweenAuditoryAndSemanticPart, "centre", 30, "bottom", demo.font$, demo.fontSize/2.0, "0", "5" demo Text special: 0.625 * boundaryBetweenAuditoryAndSemanticPart, "centre", 30, "bottom", demo.font$, demo.fontSize/2.0, "0", "10" demo Text special: 0.725 * boundaryBetweenAuditoryAndSemanticPart, "centre", 30, "bottom", demo.font$, demo.fontSize/2.0, "0", "15" demo Text special: 0.825 * boundaryBetweenAuditoryAndSemanticPart, "centre", 30, "bottom", demo.font$, demo.fontSize/2.0, "0", "20" demo Text special: 0.915 * boundaryBetweenAuditoryAndSemanticPart, "centre", 30, "bottom", demo.font$, demo.fontSize/2.0, "0", "25" demo Text special: boundaryBetweenAuditoryAndSemanticPart, "right", 30, "bottom", demo.font$, demo.fontSize/2.0, "0", "ERB]" endif if include_meaning x# = linear# (boundaryBetweenAuditoryAndSemanticPart, 100, meaning.numberOfWords, 1) for i to meaning.numberOfWords demo Text special: x# [i], "right", 37, "half", demo.font$, demo.fontSize/3.0, "90", meaning.morpheme$ [i] endfor endif demo Line width: 2 radius = 1.5 for i to numberOfInputNodes input = activity1# [i] / 5 if input <> 0 demo Paint circle: if input > 0 then "red" else "blue" fi, x1# [i], y1, radius * abs (input) endif demo Draw circle: x1# [i], y1, radius endfor radius = 1.0 for i to numberOfMiddleNodes demo Paint circle: "red", x2# [i], y2, radius * activity2# [i] + 1e-6 demo Draw circle: x2# [i], y2, radius endfor radius = 2.0 for i to numberOfTopNodes demo Paint circle: "red", x3# [i], y3, radius * activity3# [i] + 1e-6 demo Draw circle: x3# [i], y3, radius endfor # # Draw history. # selectObject: soundDistribution demo Yellow demo Line width: 3 demo Draw rows: 0.5, numberOfInputNodes + 0.5, 0, 0, 0, step * 5 demo Colour: demo.foregroundColour$ # # Draw buttons. # demo Line width: 2 demo Select inner viewport: 0, 100, 0, 100 demo Axes: 0, 100, 0, 100 demo Text: 50, "centre", 12, "half", "After " + string$ (step) + if step = 1 then " input." else " inputs." fi y1NDC = 20 + 60/100 * y1 y2NDC = 20 + 60/100 * y2 y3NDC = 20 + 60/100 * y3 @demo.button: 14, 18, y1NDC, "1" @demo.button: 14, 18, y2NDC, "2" @demo.button: 14, 18, y3NDC, "3" if include_sound and include_meaning @demo.button: 8, 13, y1NDC, "[s]" @demo.button: 81, 85, y1NDC, "‘m’" endif demo Select inner viewport: 0, 100, 0, 100 @demo.button: 88, 98, 70, "10000↑" @demo.button: 88, 98, 60, "1000↑" @demo.button: 88, 98, 50, "100↑" @demo.button: 88, 98, 40, "10↑" @demo.button: 88, 98, 30, "1↑" @demo.button: 88, 98, 20, "new" # # Draw manual. # y = 0 if include_sound and include_meaning demo Text special: 0, "left", y, "bottom", demo.font$, demo.fontSize/3.0, "0", "To spread nonstochastically to a level, click 1/2/3, or to spread to sound or meaning only, click [s] or ‘m’." y += 2 endif if include_meaning demo Text special: 0, "left", y, "bottom", demo.font$, demo.fontSize/3.0, "0", "To input meaning, click on one morpheme node, or (to get the composed meaning) type a/e/i/o/u." y += 2 endif if include_sound demo Text special: 0, "left", y, "bottom", demo.font$, demo.fontSize/3.0, "0", "To input a vowel sound, click on two formant nodes, or (to get the category centre) type A/E/I/O/U." endif # # User interaction loop. # while demoWaitForInput ( ) if demoClickedIn (88, 98, 20-4, 20+4) or demoInput ("n") ; new removeObject: soundDistribution goto NETWORK elsif demoClickedIn (20, 80, 20, 50) demo Select inner viewport: 20, 80, 20, 80 clickedInputNode = 0.5 + demoX ( ) / 100 * numberOfInputNodes clickedInAuditoryPart = ( clickedInputNode <= semf.offsetNode + 0.5 ) if clickedInAuditoryPart #Determine in which slab is clicked. clickedInSlab1 = ( clickedInputNode <= numberOfAuditoryNodesPerSlab + 0.5) if clickedInSlab1 if halfwayClickedTwoFormantsSlab1 clickedAuditoryNode = clickedInputNode activity1# ~ if col <= numberOfAuditoryNodesPerSlab ... then self + 5 * exp (-0.5 * ((col - clickedAuditoryNode) / auditorySpreading_nodes) ^ 2) - 0.5 ... else if col <= numberOfAuditoryNodes ... then self ... else 0 ... fi ... fi clickedFormant2_erb_Slab1 = fmin_erb + (clickedAuditoryNode - 1) * erbsPerNode clickedFormant2_erb_Slab2 = fmin_erb + (clickedAuditoryNode - 1) * erbsPerNode @speak: clickedFormant1_erb_Slab1, clickedFormant2_erb_Slab1, clickedFormant1_erb_Slab2, clickedFormant2_erb_Slab2 halfwayClickedTwoFormantsSlab1 = 0 else clickedAuditoryNode = clickedInputNode activity1# ~ if col <= numberOfAuditoryNodesPerSlab ... then 5 * exp (-0.5 * ((col - clickedAuditoryNode) / auditorySpreading_nodes) ^ 2) - 0.5 ... else if col <= numberOfAuditoryNodes ... then self ... else 0 ... fi ... fi clickedFormant1_erb_Slab1 = fmin_erb + (clickedAuditoryNode - 1) * erbsPerNode clickedFormant1_erb_Slab2 = fmin_erb + (clickedAuditoryNode - 1) * erbsPerNode halfwayClickedTwoFormantsSlab1 = 1 endif else if halfwayClickedTwoFormantsSlab2 clickedAuditoryNode = clickedInputNode activity1# ~ if col <= numberOfAuditoryNodesPerSlab ... then self ... else if col <= numberOfAuditoryNodes ... then self + 5 * exp (-0.5 * ((col - clickedAuditoryNode) / auditorySpreading_nodes) ^ 2) - 0.5 ... else 0 ... fi ... fi clickedFormant2_erb_Slab2 = fmin_erb + (clickedAuditoryNode - numberOfAuditoryNodesPerSlab - 1) * erbsPerNode @speak: clickedFormant1_erb_Slab1, clickedFormant2_erb_Slab1, clickedFormant1_erb_Slab2, clickedFormant2_erb_Slab2 halfwayClickedTwoFormantsSlab2 = 0 else clickedAuditoryNode = clickedInputNode activity1# ~ if col <= numberOfAuditoryNodesPerSlab ... then self ... else if col <= numberOfAuditoryNodes ... then 5 * exp (-0.5 * ((col - clickedAuditoryNode) / auditorySpreading_nodes) ^ 2) - 0.5 ... else 0 ... fi ... fi clickedFormant1_erb_Slab2 = fmin_erb + (clickedAuditoryNode - numberOfAuditoryNodesPerSlab - 1) * erbsPerNode halfwayClickedTwoFormantsSlab2 = 1 endif endif else clickedMeaningNode = round (clickedInputNode - semf.offsetNode) activity1# ~ if col <= semf.offsetNode ... then 0 ... else 5 * if col - semf.offsetNode = clickedMeaningNode then 1.0 else - 1 / (meaning.numberOfWords - 1) fi ... fi endif demo Select inner viewport: 0, 100, 0, 100 activity2# = zero# (numberOfMiddleNodes) activity3# = zero# (numberOfTopNodes) goto NETWORK_NEXT elsif demoClickedIn (14, 18, y1NDC-4, y1NDC+4) or demoInput ("1") activity1# = mul# (weight12##, activity2#) + bias1# goto NETWORK_NEXT elsif demoClickedIn (14, 18, y2NDC-4, y2NDC+4) or demoInput ("2") activity2# = sigmoid# (mul# (activity1#, weight12##) + mul# (weight23##, activity3#) + bias2#) goto NETWORK_NEXT elsif demoClickedIn (14, 18, y3NDC-4, y3NDC+4) or demoInput ("3") activity3# = sigmoid# (mul# (activity2#, weight23##) + bias3#) goto NETWORK_NEXT elsif include_meaning and demoClickedIn (8, 13, y1NDC-4, y1NDC+4) or demoInput ("s") activity1_wide# = mul# (weight12##, activity2#) + bias1# activity1# ~ if col <= semf.offsetNode then activity1_wide# [col] else self fi goto NETWORK_NEXT elsif include_meaning and demoClickedIn (81, 85, y1NDC-4, y1NDC+4) or demoInput ("m") activity1_wide# = mul# (weight12##, activity2#) + bias1# activity1# ~ if col <= semf.offsetNode then self else activity1_wide# [col] fi goto NETWORK_NEXT elsif demoInput ("AEIOU") if include_sound if firstVowel clickedVowel1 = index ("AEIOU", demoKey$ ()) f1_erb_slab1 = randomGauss (f1_erb# [clickedVowel1], ambientStdev_erb) f2_erb_slab1 = randomGauss (f2_erb# [clickedVowel1], ambientStdev_erb) @cleanInput firstVowel = 0 else clickedVowel2 = index ("AEIOU", demoKey$ ()) f1_erb_slab2 = randomGauss (f1_erb# [clickedVowel2], ambientStdev_erb) f2_erb_slab2 = randomGauss (f2_erb# [clickedVowel2], ambientStdev_erb) @cleanInput @applySound: f1_erb_slab1, f2_erb_slab1, f1_erb_slab2, f2_erb_slab2, 0 @spreadUp: 0 ;@resonate: 0 @speak: f1_erb_slab1, f2_erb_slab1, f1_erb_slab2, f2_erb_slab2 firstVowel = 1 endif endif goto NETWORK_NEXT elsif demoInput ("aeiou") if include_sound if firstMeaningVowel clickedMeaningVowel1$ = demoKey$ () firstMeaningVowel = 0 else clickedMeaningVowel2$ = demoKey$ () firstMeaningVowel = 1 clickedMeaning$ = "‘" + clickedMeaningVowel1$ + clickedMeaningVowel2$ + "’" for i to meaning.numberOfWords if meaning.morpheme$ [i] = clickedMeaning$ clickedWord = i @cleanInput @applyMeaning: clickedWord @spreadUp: 0 ;@resonate: 0 endif endfor endif endif goto NETWORK_NEXT # Similarity between sounds elsif demoInput ("S") similarity## = zero## (meaning.numberOfWords, meaning.numberOfWords) for iword to meaning.numberOfWords ivowel_slab1$ = mid$( meaning.morpheme$ [iword], 2) ivowel_slab1 = index (vowels$, ivowel_slab1$) ivowel_slab2$ = mid$( meaning.morpheme$ [iword], 3) ivowel_slab2 = index (vowels$, ivowel_slab2$) for jword to meaning.numberOfWords jvowel_slab1$ = mid$( meaning.morpheme$ [jword], 2) jvowel_slab1 = index (vowels$, jvowel_slab1$) jvowel_slab2$ = mid$( meaning.morpheme$ [jword], 3) jvowel_slab2 = index (vowels$, jvowel_slab2$) @cleanInput @applySound: f1_erb# [ivowel_slab1], f2_erb# [ivowel_slab1], f1_erb# [ivowel_slab2], f2_erb# [ivowel_slab2], 0 @spreadUp: 0 @resonate: 0 activity_ivowel# = activity2# @cleanInput @applySound: f1_erb# [jvowel_slab1], f2_erb# [jvowel_slab1], f1_erb# [jvowel_slab2], f2_erb# [jvowel_slab2], 0 @spreadUp: 0 @resonate: 0 activity_jvowel# = activity2# similarity = inner (activity_ivowel#, activity_jvowel#) / norm (activity_ivowel#) / norm (activity_jvowel#) similarity## [iword, jword] = round (similarity * 100) endfor endfor writeInfoLine: "Similarity of sounds: ", newline$, similarity## # Similarity between meaning morphemes elsif demoInput ("M") similarity## = zero## (meaning.numberOfWords, meaning.numberOfWords) for iword to meaning.numberOfWords for jword to meaning.numberOfWords @cleanInput @applyMeaning: iword @spreadUp: 0 @resonate: 0 activity_ivowel# = activity2# @cleanInput @applyMeaning: jword @spreadUp: 0 @resonate: 0 activity_jvowel# = activity2# similarity = inner (activity_ivowel#, activity_jvowel#) / norm (activity_ivowel#) / norm (activity_jvowel#) similarity## [iword, jword] = round (similarity * 100) endfor endfor writeInfoLine: "Similarity of morphemes: ", newline$, similarity## # Find activity of meaning nodes elsif demoInput ("N") meaning_activity# = zero# (meaning.numberOfWords) for meaning_activity from numberOfAuditoryNodes to k @cleanInput @applyMeaning: meaning_activity @spreadUp: 0 @resonate: 0 activity_ivowel# = activity1# endfor writeInfoLine: "Activity of meaning nodes", newline$ for activity from (numberOfAuditoryNodes + 1) to size (activity1#) appendInfo: fixed$ (activity1# [activity], 3) + ", " endfor # Draw the network in Praat Picture elsif demoInput ("D") Select inner viewport: 0.5, 11, 0.4, 6 Axes: 0, 100, 0, 100 Paint rectangle: "silver", 0, 100, 0, 100 for i to numberOfInputNodes for j to numberOfMiddleNodes weight = weight12## [i, j] if weight > 0 Black Line width: weight Draw line: x1# [i], y1, x2# [j], y2 elsif weight < 0 White Line width: abs (weight) Draw line: x1# [i], y1, x2# [j], y2 endif endfor endfor for i to numberOfMiddleNodes for j to numberOfTopNodes weight = weight23## [i, j] if weight > 0 Black Line width: weight Draw line: x2# [i], y2, x3# [j], y3 elsif weight < 0 White Line width: abs (weight) Draw line: x2# [i], y2, x3# [j], y3 endif endfor endfor Black boundaryBetweenAuditoryAndSemanticPart = semf.offsetNode / numberOfInputNodes * 100 if include_sound Text special: 0, "left", 30, "bottom", demo.font$, demo.fontSize/2.0, "0", "[" Text special: 0.025 * boundaryBetweenAuditoryAndSemanticPart, "centre", 30, "bottom", demo.font$, demo.fontSize/2.0, "0", "5" Text special: 0.125 * boundaryBetweenAuditoryAndSemanticPart, "centre", 30, "bottom", demo.font$, demo.fontSize/2.0, "0", "10" Text special: 0.225 * boundaryBetweenAuditoryAndSemanticPart, "centre", 30, "bottom", demo.font$, demo.fontSize/2.0, "0", "15" Text special: 0.325 * boundaryBetweenAuditoryAndSemanticPart, "centre", 30, "bottom", demo.font$, demo.fontSize/2.0, "0", "20" Text special: 0.425 * boundaryBetweenAuditoryAndSemanticPart, "centre", 30, "bottom", demo.font$, demo.fontSize/2.0, "0", "25" Text special: 0.470 * boundaryBetweenAuditoryAndSemanticPart, "centre", 30, "bottom", demo.font$, demo.fontSize/2.0, "0", "]" Text special: 0.475 * boundaryBetweenAuditoryAndSemanticPart, "centre", 30, "bottom", demo.font$, demo.fontSize/2.0, "0", "[" Text special: 0.525 * boundaryBetweenAuditoryAndSemanticPart, "centre", 30, "bottom", demo.font$, demo.fontSize/2.0, "0", "5" Text special: 0.625 * boundaryBetweenAuditoryAndSemanticPart, "centre", 30, "bottom", demo.font$, demo.fontSize/2.0, "0", "10" Text special: 0.725 * boundaryBetweenAuditoryAndSemanticPart, "centre", 30, "bottom", demo.font$, demo.fontSize/2.0, "0", "15" Text special: 0.825 * boundaryBetweenAuditoryAndSemanticPart, "centre", 30, "bottom", demo.font$, demo.fontSize/2.0, "0", "20" Text special: 0.915 * boundaryBetweenAuditoryAndSemanticPart, "centre", 30, "bottom", demo.font$, demo.fontSize/2.0, "0", "25" Text special: boundaryBetweenAuditoryAndSemanticPart, "right", 30, "bottom", demo.font$, demo.fontSize/2.0, "0", "ERB]" endif if include_meaning x# = linear# (boundaryBetweenAuditoryAndSemanticPart, 100, meaning.numberOfWords, 1) for i to meaning.numberOfWords Text special: x# [i], "right", 37, "half", demo.font$, demo.fontSize/3.0, "90", meaning.morpheme$ [i] endfor endif Line width: 2 radius = 1.5 for i to numberOfInputNodes input = activity1# [i] / 5 if input <> 0 Paint circle: if input > 0 then "black" else "grey" fi, x1# [i], y1, radius * abs (input) endif Draw circle: x1# [i], y1, radius endfor radius = 1.0 for i to numberOfMiddleNodes Paint circle: "black", x2# [i], y2, radius * activity2# [i] + 1e-6 Draw circle: x2# [i], y2, radius endfor radius = 2.0 for i to numberOfTopNodes Paint circle: "black", x3# [i], y3, radius * activity3# [i] + 1e-6 Draw circle: x3# [i], y3, radius endfor elsif demoInput ("F") endif numberOfSteps = ... if demoClickedIn (88, 98, 30-4, 30+4) or demoInput ("↑") then 1 else ... if demoClickedIn (88, 98, 40-4, 40+4) then 10 else ... if demoClickedIn (88, 98, 50-4, 50+4) then 100 else ... if demoClickedIn (88, 98, 60-4, 60+4) then 1000 else ... if demoClickedIn (88, 98, 70-4, 70+4) then 10000 else 0 fi fi fi fi fi if numberOfSteps <> 0 for ministep to abs (numberOfSteps) step += 1 word = randomInteger (1, meaning.numberOfWords) vowel_slab1$ = mid$( meaning.morpheme$ [word], 2) vowel_slab1 = index (vowels$, vowel_slab1$) vowel_slab2$ = mid$( meaning.morpheme$ [word], 3) vowel_slab2 = index (vowels$, vowel_slab2$) f1_slab1 = randomGauss (f1_erb# [vowel_slab1], ambientStdev_erb) f2_slab1 = randomGauss (f2_erb# [vowel_slab1], ambientStdev_erb) f1_slab2 = randomGauss (f1_erb# [vowel_slab2], ambientStdev_erb) f2_slab2 = randomGauss (f2_erb# [vowel_slab2], ambientStdev_erb) @cleanInput if include_sound @applySound: f1_slab1, f2_slab1, f1_slab2, f2_slab2, 1 endif if include_meaning @applyMeaning: word endif @learn: learningRate if numberOfSteps = 1 @speak: f1_slab1, f2_slab1, f1_slab2, f2_slab2 endif endfor goto NETWORK_NEXT endif goto NETWORK_END demoInput ("← →") endwhile label NETWORK_NEXT until 0 label NETWORK_END # # Clean up history. # removeObject: soundDistribution procedure cleanInput activity1# ~ 0.0 endproc procedure applySound: .f1_erb_slab1, .f2_erb_slab1, .f1_erb_slab2, .f2_erb_slab2, .recordSoundDistribution .audNode1_slab1 = 1 + (.f1_erb_slab1 - fmin_erb) / erbsPerNode .audNode2_slab1 = 1 + (.f2_erb_slab1 - fmin_erb) / erbsPerNode .audNode1_slab2 = 1 + numberOfAuditoryNodesPerSlab + (.f1_erb_slab2 - fmin_erb) / erbsPerNode .audNode2_slab2 = 1 + numberOfAuditoryNodesPerSlab + (.f2_erb_slab2 - fmin_erb) / erbsPerNode activity1# ~ if col > numberOfAuditoryNodes then self else ... 5 * exp (-0.5 * ((col - .audNode1_slab1) / auditorySpreading_nodes) ^ 2) + ... 5 * exp (-0.5 * ((col - .audNode2_slab1) / auditorySpreading_nodes) ^ 2) - 1 + ... 5 * exp (-0.5 * ((col - .audNode1_slab2) / auditorySpreading_nodes) ^ 2) + ... 5 * exp (-0.5 * ((col - .audNode2_slab2) / auditorySpreading_nodes) ^ 2) - 1 ... fi if .recordSoundDistribution select soundDistribution Formula: ~ self + activity1# [col] + 2 endif endproc procedure applyMeaning: .word activity1# ~ if col <= semf.offsetNode then self else -5 / (meaning.numberOfWords - 1) fi activity1# [semf.offsetNode + .word] = 5 endproc procedure speak: .f1_erb_slab1, .f2_erb_slab1, .f1_erb_slab2, .f2_erb_slab2 .f1_Slab1 = erbToHertz (.f1_erb_slab1) .f2_Slab1 = erbToHertz (.f2_erb_slab1) .f1_Slab2 = erbToHertz (.f1_erb_slab2) .f2_Slab2 = erbToHertz (.f2_erb_slab2) runScript: "makeDiphthong.praat", .f1_Slab1, .f2_Slab1, .f2_Slab1 + 1000, .f2_Slab1 + 1900, ... .f1_Slab2, .f2_Slab2, .f2_Slab2 + 1000, .f2_Slab2 + 1900, 80, 160, 360, 530, 80, 160, 360, 530, 150, 0.5 asynchronous Play plusObject: "KlattGrid kg" Remove endproc include demo.praatinclude