Votrax SC-01A PWM clocked
03/10/2012The idea
I got this brilliant idea by John Loadsman who is using a version of my previous code: http://www.youtube.com/watch?v=tUbTZU_FCz0&feature=context-cha
I also wanted to digitally control the Votrax’s pitch to implement some new functions. (keep in mind that I want the Votrax to sing)
The hardware modification was pretty easy: I removed the analog clocking part, tied the MCRC to the ground and just pulled the Votrax’s clock entry MCX to +5v with a 2.2k resistor.
I had to use pin 3 on the Arduino to produce the clock via the timer 2 and, therefore, need to use pin 6 for the A/R
Code
What’s new
– Moved the A/R to pin 6
– Using pin 3 to generate the clock (see setup section)
– Created a function to drive the clock on demand. See ClockFrequency() where the clock frequency is given in kHz.
– note: My Votrax doesn’t seem to accept a frequency bigger than 910 kHz
– Added some new modifier _PITCHUP & _PITCHDN to allow variation within the text
Todo :
– find a way to produce musical notes
– Add midi control
/* Votrax SC-O1A Speech Chip
Sing n' Speech Processor
Arduino Uno
Updated to use timer to generate the clock (an excellent idea by John Loadsman (August 2012)
Changes (03/10/2012)
- Moved the A/R to pin 6
- Using pin 3 to generate the clock (see setup section)
- Created a function to drive the clock on demand (see ClockFrequency() where the clock frequency is given in kHz)
- Added some new modifier _PITCHUP & _PITCHDN to allow variation within the text
**********************************************************************
___ ___
Vp 1 |* \_/ | 28 A0
I2 2 | | 21 AF
I1 3 | | 20 CB
NC 4 | | 19 NC
TP3 5 | Votrax | 18 Vg
TP2 6 | SC-01 A | 17 TP1
STB 7 | | 16 MCRC
A/R 8 | | 15 MCX
P5 9 | | 14 P0
P4 10 | | 13 P1
P3 11 |_________| 12 P2
**********************************************************************
*/
int sensorPin = A5; // Manuel speed setting via potentiometer as voltage divider on pin 5
#define PIN_STB 2 // Strobe need to go high to latch datas
#define PIN_AR 6 // Acknowledge/Request goes high when ready (was 3)
#define PIN_I1 5 // Inflection bit1 (votrax pin 3)
#define PIN_I2 4 // Inflection bit2 (vot pin 2)
#define PIN_TIMING 7 // read the switch's status
// define all the phonemes
#define _EH3 0x00 // 59 MS ;JACKET
#define _EH2 0x01 // 71 MS ;ENLIST
#define _EH1 0x02 // 121MS ;HEAVY
#define _PA0 0x03 // 47 MS ;NO SOUND
#define _DT 0x04 // 47 MS ;BUTTER
#define _A2 0x05 // 71 MS ;MADE
#define _A1 0x06 // 103MS ;MADE
#define _ZH 0x07 // 90 MS ;AZURE
#define _AH2 0x08 // 71 MS ;HONEST -
#define _I3 0x09 // 55 MS ;INHIBIT
#define _I2 0x0A // 80 MS ;INHIBIT
#define _I1 0x0B // 121MS ;INHIBIT
#define _M 0x0C // 103MS ;MAT
#define _N 0x0D // 80 MS ;SUN
#define _B 0x0E // 71 MS ;BAG
#define _V 0x0F // 71 MS ;VAN
#define _CH 0x10 // 71 MS ;CHIP
#define _SH 0x11 // 121MS ;SHOP
#define _Z 0x12 // 71 MS ;ZOO
#define _AW1 0x13 // 146MS ;LAWFUL
#define _NG 0x14 // 121MS ;THING
#define _AH1 0x15 // 146MS ;FATHER
#define _OO1 0x16 // 103MS ;LOOKING
#define _OO 0x17 // 185MS ;BOOK
#define _L 0x18 // 103MS ;LAND
#define _K 0x19 // 80 MS ;TRICK
#define _J 0x1A // 47 MS ;JUDGE
#define _H 0x1B // 71 MS ;HELLO
#define _G 0x1C // 71 MS ;GET
#define _F 0x1D // 103MS ;FAST
#define _D 0x1E // 55 MS ;PAID
#define _S 0x1F // 90 MS ;PASS
#define _A 0x20 // 185MS ;DAY
#define _AY 0x21 // 65 MS ;DAY
#define _Y1 0x22 // 80 MS ;YARD
#define _UH3 0x23 // 47 MS ;MISSION
#define _AH 0x24 // 250MS ;MOP
#define _P 0x25 // 103MS ;PAST
#define _O 0x26 // 185MS ;COLD
#define _I 0x27 // 185MS ;PIN
#define _U 0x28 // 185MS ;MOVE
#define _Y 0x29 // 103MS ;ANY
#define _T 0x2A // 71 MS ;TAP
#define _R 0x2B // 90 MS ;RED
#define _E 0x2C // 185MS ;MEET
#define _W 0x2D // 80 MS ;WIN
#define _AE 0x2E // 185MS ;DAD
#define _AE1 0x2F // 103MS ;AFTER
#define _AW2 0x30 // 90 MS ;SALTY
#define _UH2 0x31 // 71 MS ;ABOUT
#define _UH1 0x32 // 103MS ;UNCLE
#define _UH 0x33 // 185MS ;CUP
#define _O2 0x34 // 80 MS ;FOR
#define _O1 0x35 // 121MS ;ABOARD
#define _IU 0x36 // 59 MS ;YOU
#define _U1 0x37 // 90 MS ;YOU
#define _THV 0x38 // 80 MS ;THE
#define _TH 0x39 // 71 MS ;THIN
#define _ER 0x3A // 146MS ;BIRD
#define _EH 0x3B // 185MS ;GET
#define _E1 0x3C // 121MS ;BE
#define _AW 0x3D // 250MS ;CALL
#define _PA1 0x3E // 185MS ;NO SOUND
#define _STOP 0x3F // 47 MS ;NO SOUND
#define _END 99 // End of phrase
#define _INFL0 100 // Inflection 0 (default mode)
#define _INFL1 101 // Inflection 1
#define _INFL2 102 // Inflection 2
#define _INFL3 103 // Inflection 3
#define _HOLD1 200 // wait 300 ms
#define _HOLD2 201 // wait 600 ms
#define _PITCHDN 202 // get pitch down
#define _PITCHUP 203 // get pitch up
void ClockFrequency(float freq)
{
long topv = (long) ((float) F_CPU /(freq*1000 ));
OCR2A = (int)((float) topv)-1;
}
void setup()
{
DDRB = B00111111; // set Port B 6 lowest bit as Output (Arduino Uno pin 8 to 13)
pinMode(PIN_TIMING,INPUT);
pinMode(PIN_STB, OUTPUT);
pinMode(PIN_AR, INPUT);
pinMode(PIN_I1, OUTPUT);
pinMode(PIN_I2, OUTPUT);
digitalWrite(PIN_I1, LOW); // default to no inflection
digitalWrite(PIN_I2, LOW); // default to no inflection
digitalWrite(PIN_STB, LOW); // must stay low
// PWM outputs via timer 2 (Arduino uno digital pin 3)
pinMode(3, OUTPUT); // enable the PWM output
TCCR2A = B00100011; // Fast PWM change at OCR2
TCCR2B = B11001; // Timer running at full system clock
OCR2A = 21; // output frequency = 16,000,000/(OCR5A+1) 21 ==> 727272 Hz, 18 ==> 842105 Hz
pinMode(3, OUTPUT); // enable the PWM output (you now have a PWM signal on digital pin 3)
OCR2B = 11; // 50% duty cycle
}
void loop()
{
ClockFrequency(600);
byte radioactive[]={
_INFL2,
_T,_CH,_ER,_HOLD1,_N,_O,_HOLD1,_B,_INFL3,_I,_HOLD1,_L,_PA1,_HOLD1,_INFL1, // Tchernobyl
_H,_A1,_HOLD1,_R,_E,_HOLD1,_S,_B,_ER,_HOLD1,_G,_HOLD1, // Harrisburg
_S,_EH1,_HOLD1,_L,_AH2,_HOLD1,_F,_INFL2,_E,_HOLD1,_L,_D,_PA1,_INFL2,_HOLD1, // Sellafield
_F,_PITCHDN,_U,_HOLD2,_K,_PITCHDN,_U,_HOLD2,_SH,_PITCHDN,_E,_HOLD2,_M,_INFL0,_PITCHUP,_PITCHUP,_PITCHUP,_PITCHUP,_AW2,_HOLD2,_HOLD2, // Fukushima
_STOP };
speak (radioactive);
ClockFrequency(730);
byte votrax[]={
_INFL0,
_V,_O,_T,_R,_UH,_K,_S,_PA1, // Votrax
_INFL1,_EH1, _EH2, _S,_PA0, // S
_S, _E1, _Y,_PA0, // C
_Z,_AY,_I1,_R,_O1,_U1,_PA0, // Zero
_W,_UH1,_UH2,_N,_PA0, // One
_A,_AY,_Y,_PA1,_INFL2, // A
_S,_P,_E1,_Y,_T,_CH,_PA0, // Speech
_S,_I,_N,_T,_EH2,_S, _AH1,_E1,_Z,_ER,_PA0,_INFL3, // Synthesizer
_R, _EH1, _EH3, _D, _Y,_STOP }; // Ready
// speak (votrax);
byte dalek7[]={_INFL2, 0x38,0x33,0x03,_INFL3,0x1e,0x24,0x18,_INFL2,0x02,0x19,0x1f,0x15,0x15,0x2b,0x38,0x33,0x1f,0x36,0x25,0x27,0x2b,0x22,_PITCHDN,0x3a,0x0e,0x2c,0x0b,0x14, 0x3e,_PA1,_HOLD2,0x3f};
//"The Daleks are the superior being."
speak (dalek7);
byte inflection[]={
_INFL0,_V,_O,_T,_R,_UH,_K,_S,_PA1, // Votrax
_INFL1,_V,_O,_T,_R,_UH,_K,_S,_PA1,
_INFL2,_V,_O,_T,_R,_UH,_K,_S,_PA1,
_INFL3,_V,_O,_T,_R,_UH,_K,_S,_PA1,
_STOP };
ClockFrequency(910);
speak (inflection);
delay(2000); // delay 2 sec between repetition
}
void speak (byte* message){
int i=0;
do
{
say(message[i]);
i++;
}
while (message[i-1]!=_STOP);
}
void say(byte phoneme) {
if (digitalRead(PIN_TIMING) ==1) { // Read the switch's status
// Wait for PIN_AR=1 when chip is ready : internal timing
while (digitalRead(PIN_AR) == 0);
}
else // if switch is low get timing via pot's value
{
int sensorValue = analogRead(sensorPin);
int sustain = map (sensorValue,0,1023,40,300);
delay(sustain);
}
switch (phoneme) {
case _INFL0:
digitalWrite(PIN_I1, LOW);
digitalWrite(PIN_I2, LOW);
break;
case _INFL1:
digitalWrite(PIN_I1, HIGH);
digitalWrite(PIN_I2, LOW);
break;
case _INFL2:
digitalWrite(PIN_I1, LOW);
digitalWrite(PIN_I2, HIGH);
break;
case _INFL3:
digitalWrite(PIN_I1, HIGH);
digitalWrite(PIN_I2, HIGH);
break;
case _HOLD1:
delay (300);
break;
case _HOLD2:
delay (600);
break;
case _PITCHDN:
OCR2A=OCR2A+4;
break;
case _PITCHUP:
OCR2A=OCR2A-4;
break;
default:
PORTB = phoneme;
// Set PIN_STB = 1 for 2usec to tell the chip to read the Port
digitalWrite(PIN_STB, HIGH);
delayMicroseconds(2);
digitalWrite(PIN_STB, LOW);
}
}
Audio

