SP0256-AL2 speech synthesis
chip
-main.bas
main.bas
Option Explicit
'--------------------------------------------------------------------------------
' Pin labels (i/o relative to BX)
' ALD (output) - Address Load, asserted low. Latches values
' at address pins A1..A8 into memory
' LRQ (input) - Load Request. asserted low. Indicates chip
' is ready to accept a new phoneme address
' SBY (input) - Standby. Asserted when chip has stopped
' talking and no new address has been
' loaded
' SBYRESET (output) - Asserted low. Resets interface and
' address values
' RESET(output) - Asserted low. Resets chip
' TEST(output) - Not clearly documented. Grounded for
' normal operation.
const ALD as byte = 13
const LRQ as byte = 14
const SBY as byte = 15
const SBYRESET as byte = 16
const RESET as byte = 17
const TEST as byte = 18
' NOTE: portc (pins 5-12) used as phoneme address, although only
' the 6 lowest order bits are used
const redButtonPin as byte = 20
const blackButtonPin as byte = 19
const cycleMode as byte = 1
const studentMode as byte = 2
' Vowel Arrays. Definied and initialized in Allophones module.
public ShortVowelArray(1 to ShortVowelArrayLength) as byte
public LongVowelArray(1 to LongVowelArrayLength) as byte
public ResonantArray(1 to ResonantArrayLength) as byte
public VoicedFricativeArray(1 to VoicedFricativeArrayLength) as byte
public VoicelessFricativeArray(1 to VoicelessFricativeArrayLength) as byte
public VoicedStopArray(1 to VoicedStopArrayLength) as byte
public VoicelessStopArray(1 to VoicelessStopArrayLength) as byte
public NasalArray(1 to NasalArrayLength) as byte
public RColoredArray(1 to RColoredArrayLength) as byte
' The AllophoneQueue is used to queue up phonemes to be
' uttered by the Say() subroutine
const AllophoneQueueMax as byte = 25
dim AllophoneQueue(1 to AllophoneQueueMax) as byte
dim AllophoneQueueSize as Byte
dim mode as byte
'--------------------------------------------------------------------------------
public sub Main()
Call LEDInit()
Call SetUpSP0256()
Call InitializePhonemeArrays()
AllophoneQueueSize = 0
dim redButtonValue as byte
dim blackButtonValue as byte
dim utterDelay as single
' Turn green onboard LED on; red off
putPin 25, 1
putpin 26, 0
' Device will behave in one of two ways:
' If the red button is held down at start up, it goes into allophone cycling mode;
' Otherwise, it goes into selectStudent mode.
redButtonValue = getPin(redButtonPin)
if redButtonValue = 1 then
mode = cycleMode
else
mode = studentMode
end if
if mode = studentMode then
'***************** Student Selection Mode *****************************************************
' Student Selection Mode begins by greeting the class.
' In student selection mode, holding the red button down randomly selects a student
' from the class list, and the device says "I pick... so and so".
'
' If no random selection has been made, pressing the black button runs through the class list
' in alphabetical order.
'
' If at least one random selection has been made, pressing the black button makes the device
' say: The robot has spoken!
'**********************************************************************************************
dim firstTime as Boolean
firstTime = True
SayGoodMorningClass
do
blackButtonValue = getPin(blackButtonPin)
redButtonValue = getPin(redButtonPin)
if blackButtonValue = 1 then
if firstTime then
SayAllStudents
else
sayTheRobotHasSpoken
end if
end if
if redButtonValue = 1 then
firstTime = False
' Randomly select a student. We'll do this by timing
' how long the button is held down with a very fast timer.
' By including timer1.bas (which comes with the bx) we get
' access to special precision timer functions:
dim timerCount as long
dim studentNumber as byte
InitializeTimer(3)
StartTimer
do while getPin(redButtonPin) = 1 'while the red button is held down...
'...make a funny sound:
Call Cycle(ShortVowelArray, ShortVowelArrayLength, 3, 0.01)
loop
call GetTimerCount(timerCount)
' timer is so fast its result is essentially random;
' when the value is modded by the class size we get a random number
' between 1 and the class size
studentNumber = cByte((timerCount mod 21) + 1)
' Clear the Allophone Queue and stop the speech:
AllophoneQueueSize = 0
add(p10ms)
say
delay 1.0
' Tell the class which student has been selected:
sayIPick
delay 1.0
call pickStudent(studentNumber)
end if
loop
else
do 'allophone looping
utterDelay = 0.35
debug.print "Long Vowels"
Call Cycle(LongVowelArray, LongVowelArrayLength, 3, utterDelay)
debug.print "Short Vowels"
Call Cycle(ShortVowelArray, ShortVowelArrayLength, 3, utterDelay)
debug.print "Resonants"
Call Cycle(ResonantArray, ResonantArrayLength, 3, utterDelay)
debug.print "Nasals"
Call Cycle(NasalArray, NasalArrayLength, 3, utterDelay)
debug.print "Voiced Stops"
Call Cycle(VoicedStopArray, VoicedStopArrayLength, 3, utterDelay)
debug.print "Voiced Fricatives"
Call Cycle(VoicedFricativeArray, VoicedFricativeArrayLength, 3, utterDelay)
debug.print "RColored Vowels"
Call Cycle(RColoredArray, RColoredArrayLength, 3, utterDelay)
debug.print "Voiceless Fricatives"
Call Cycle(VoicelessFricativeArray, VoicelessFricativeArrayLength, 3, utterDelay)
debug.print "Voiceless Stops"
Call Cycle(VoicelessStopArray, VoicelessStopArrayLength, 3, utterDelay)
delay 1.0
loop
end if
end sub 'Main
' Iniialize the SP0256
private sub SetupSP0256()
' Assert SBYRESET and RESET:
PutPin SBYRESET, 0
PutPin RESET, 0
' Ground TEST for normal operation:
PutPin TEST, 0
' Disable Address Loading (which is asserted low)
PutPin ALD, 1
' Set lower 6 bits of port C (pins 7-12) as output
Register.DDRC = 255
' Wait and let the chip chill
Delay 1.5
' Disable RESET and SBYRESET
PutPin SBYRESET, 1
PutPin RESET, 1
end sub
' Add(phoneme) : Add a phoneme to the allophone queue
sub Add(ByVal X as Byte)
' If the allophone queue is full, exit
if AllophoneQueueSize >= AllophoneQueueMax then
exit sub
end if
' Otherwise add the allophone to the end of the queue
AllophoneQueueSize = AllophoneQueueSize + 1
AllophoneQueue(AllophoneQueueSize) = x
end sub
' Say() : Pronounce all the phonemes in the queue sequentially
sub Say()
dim i as byte
for i = 1 to AllophoneQueueSize
' Put the address value on PortC
Register.PortC = AllophoneQueue(i)
' Strobe Address Load low to latch the address
PutPin ALD, 0
PutPin ALD, 1
' wait while until another Load Request
do while (GetPin(LRQ) = 1)
'nothing
loop
next
AllophoneQueueSize = 0
end sub
' Cycle(whichArray, arraySize, numberOfTimes, delayTime) : Cycle through all the sounds in a phoneme group
sub Cycle(ByRef phonemeArray() as byte, ByVal arraySize as byte, ByVal numberOfTimes as byte, ByVal delayTime as single)
dim i as byte, j as byte
for i = 1 to numberOfTimes
for j = 1 to arraySize
' put phoneme value on address pins
Register.PortC = phonemeArray(j)
' Strobe Address Load low to latch the address
PutPin ALD, 0
PutPin ALD, 1
' A delay of 0.0 will result in phonemes uttered as fast as the chip requests them via LRQ.
' Otherwise, a fixed delay time will be used, and LRQ is ignored.
if delayTime <> 0.0 then
delay delayTime
else
do while(GetPin(LRQ) = 1)
'nothing
loop
end if
next
next
end sub
' pickStudent : take a student number and say the corresponding name
sub pickStudent(ByVal whichStudent as byte)
dim count as byte
count = 0
do while count < 4
select case whichStudent
case 1
SayDesireena(0.5)
case 2
SayKaren(0.25)
case 3
SayChristine(0.125)
case 4
SayLia(0.5)
case 5
SayCarrie(0.25)
case 6
SayFaYi(0.5)
case 7
SayKatherine(0.25)
case 8
SayRachel(0.125)
case 9
SayChieh(0.5)
case 10
SayJessica(1.0)
case 11
SayMiro(0.25)
case 12
SayAi(0.75)
case 13
SayHyunJean(0.25)
case 14
SayJon(0.5)
case 15
SayMac(0.125)
case 16
SayYoonhee(0.5)
case 17
SayPatrick(0.5)
case 18
SayGabriela(0.5)
case 19
SayJose(0.5)
case 20
SayDiana(0.25)
case 21
SayJungEun(0.25)
end select
count = count + 1
delay 0.25
loop
end sub
' Little init sequence for LEDs to indicate program start
public sub LEDInit()
dim i as integer
' Turn on board LEDs (pin 25, 26) off
putPin 25, 1
putPin 26, 1
' blink red:
for i = 1 to 10
delay 0.05
putPin 25, 1
delay 0.05
putpin 25, 0
next
end sub
|