News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_Devilmarkus

Amstrad SSA-1 Speech Synthesizer ROM needed

Started by Devilmarkus, 22:50, 04 January 10

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Devilmarkus

Who can dump/send me the Amstrad SSA-1 Speech Synthesizer rom? I really need it...
When you put your ear on a hot stove, you can smell how stupid you are ...

Amstrad CPC games in your webbrowser

JavaCPC Desktop Full Release

Executioner

Do you mean the internal ROM on the SPO256AL2?

Devilmarkus

#2
I am not sure. I need the rom like the existing DK'Tronics speech rom, which contains the RSX commands and port output routines

Here's how I emulate the DK'Tronics speech:

package jemu.system.cpc;

import jemu.ui.Talker;

/**
*
* @author Markus
*/
public class Speech {

    static Talker talk;
    static Thread Speech ;
    protected static String[] Phoneme;
    protected static int[] bytes;
    public static String speechthis = "";

    public static String Translate(String input){
        String out="";
            for(int i = 0; i < input.length(); i=i+6*3){
                out+=input.charAt(i);
                out+=input.charAt(i+1);
                out+=input.charAt(i+2);
            }
        input = out;
        String result="";
        System.out.println("input:"+input);
        int len = input.length()/3;
        Phoneme = new String[len];
        bytes = new int[len];
        for (int i = 0; i < len; i++) {
            String got = input;
            Phoneme[i] = got.substring(0,2);
            input = input.substring(3);
        }
        for (int i = 0; i < len; i++){
            if (Phoneme[i].equals("00"))
                Phoneme[i]="ignore";
            else
            if (Phoneme[i].equals("01"))
                Phoneme[i]="10ms";
            else
            if (Phoneme[i].equals("02"))
                Phoneme[i]="ignore";
            else
            if (Phoneme[i].equals("03"))
                Phoneme[i]="   ";
            else
            if (Phoneme[i].equals("04"))
                Phoneme[i]="50ms";
            else
            if (Phoneme[i].equals("18"))
                Phoneme[i]="a";
            else
            if (Phoneme[i].equals("1C"))
                Phoneme[i]="b";
            else
            if (Phoneme[i].equals("08"))
                Phoneme[i]="c";
            else
            if (Phoneme[i].equals("15"))
                Phoneme[i]="d";
            else
            if (Phoneme[i].equals("07"))
                Phoneme[i]="e";
            else
            if (Phoneme[i].equals("28"))
                Phoneme[i]="f";
            else
            if (Phoneme[i].equals("24"))
                Phoneme[i]="g";
            else
            if (Phoneme[i].equals("1B"))
                Phoneme[i]="h";
            else
            if (Phoneme[i].equals("0C"))
                Phoneme[i]="i";
            else
            if (Phoneme[i].equals("0A"))
                Phoneme[i]="j";
            else
            if (Phoneme[i].equals("2A"))
                Phoneme[i]="k";
            else
            if (Phoneme[i].equals("2D"))
                Phoneme[i]="l";
            else
            if (Phoneme[i].equals("10"))
                Phoneme[i]="m";
            else
            if (Phoneme[i].equals("0B"))
                Phoneme[i]="n";
            else
            if (Phoneme[i].equals("17"))
                Phoneme[i]="o";
            else
            if (Phoneme[i].equals("09"))
                Phoneme[i]="p";
            else
            if (Phoneme[i].equals("27"))
                Phoneme[i]="r";
            else
            if (Phoneme[i].equals("37"))
                Phoneme[i]="s";
            else
            if (Phoneme[i].equals("11"))
                Phoneme[i]="t";
            else
            if (Phoneme[i].equals("0F"))
                Phoneme[i]="u";
            else
            if (Phoneme[i].equals("23"))
                Phoneme[i]="v";
            else
            if (Phoneme[i].equals("10"))
                Phoneme[i]="m";
            else
            if (Phoneme[i].equals("2E"))
                Phoneme[i]="w";
            else
            if (Phoneme[i].equals("31"))
                Phoneme[i]="y";
            else
            if (Phoneme[i].equals("2B"))
                Phoneme[i]="z";
            else

            if (Phoneme[i].equals("14"))
                Phoneme[i]="aa";
            else
            if (Phoneme[i].equals("13"))
                Phoneme[i]="ee";
            else
            if (Phoneme[i].equals("06"))
                Phoneme[i]="ii";
            else
            if (Phoneme[i].equals("35"))
                Phoneme[i]="oo";
            else
            if (Phoneme[i].equals("3F"))
                Phoneme[i]="bb";
            else
            if (Phoneme[i].equals("21"))
                Phoneme[i]="dd";
            else
            if (Phoneme[i].equals("3D"))
                Phoneme[i]="gg";
            else
            if (Phoneme[i].equals("22"))
                Phoneme[i]="ggg";
            else
            if (Phoneme[i].equals("39"))
                Phoneme[i]="hh";
            else
            if (Phoneme[i].equals("3E"))
                Phoneme[i]="ii";
            else
            if (Phoneme[i].equals("38"))
                Phoneme[i]="nn";
            else
            if (Phoneme[i].equals("0E"))
                Phoneme[i]="rr";
            else
            if (Phoneme[i].equals("0D"))
                Phoneme[i]="tt";
            else
            if (Phoneme[i].equals("19"))
                Phoneme[i]="yy";
            else
            if (Phoneme[i].equals("3B"))
                Phoneme[i]="ar";
            else
            if (Phoneme[i].equals("2F"))
                Phoneme[i]="aer";
            else
            if (Phoneme[i].equals("32"))
                Phoneme[i]="ch";
            else
            if (Phoneme[i].equals("29"))
                Phoneme[i]="ck";
            else
            if (Phoneme[i].equals("3C"))
                Phoneme[i]="ear";
            else
            if (Phoneme[i].equals("1A"))
                Phoneme[i]="eh";
            else
            if (Phoneme[i].equals("33"))
                Phoneme[i]="er";
            else
            if (Phoneme[i].equals("34"))
                Phoneme[i]="err";
            else
            if (Phoneme[i].equals("2C"))
                Phoneme[i]="ng";
            else
            if (Phoneme[i].equals("3A"))
                Phoneme[i]="or";
            else
            if (Phoneme[i].equals("16"))
                Phoneme[i]="ou";
            else
            if (Phoneme[i].equals("1F"))
                Phoneme[i]="ouu";
            else
            if (Phoneme[i].equals("20"))
                Phoneme[i]="ow";
            else
            if (Phoneme[i].equals("05"))
                Phoneme[i]="oy";
            else
            if (Phoneme[i].equals("25"))
                Phoneme[i]="sh";
            else
            if (Phoneme[i].equals("1D"))
                Phoneme[i]="th";
            else
            if (Phoneme[i].equals("12"))
                Phoneme[i]="dth";
            else
            if (Phoneme[i].equals("1E"))
                Phoneme[i]="uh";
            else
            if (Phoneme[i].equals("30"))
                Phoneme[i]="wh";
            else
            if (Phoneme[i].equals("21"))
                Phoneme[i]="zh";
            else{
                System.err.println("Unknown speech command " + Phoneme[i]);
                Phoneme[i]="ignore";}
        }

        speechthis = "";
        out="";
        for (int i = 0; i < len; i++)
            if (!Phoneme[i].equals("ignore"))
                out+=Phoneme[i]+"|";
        say (out);
        return result;
    }
        /*ALLOPHONE DECIMAL HEX ALLOPHONE DECIMAL HEX
                a 24 18 (aa) or (ay) 20 14
                b 28 1c      (ee) 19 13
                c 8 08      (ii) 6 06
                d 21 15  (oo) or (eau) 53 35
                e 7 07      (bb) 63 3f
                f 40 28      (dd) 33 21
                g 36 24      (gg) 61 3d
                h 27 1b      (ggg) 34 22
                i 12 0c      (hh) 57 39
                j 10 0a      (ii) 62 3e
                k 42 2a      (nn) 56 38
                l 45 2d      (rr) 14 0e
                m 16 10      (tt) 13 0d
                n 11 0b      (yy) 25 19
                o 23 17      (ar) 59 3b
                p 9 9       (aer) 47 2f
                r 39 27      (ch) 50 32
                s 55 37      (ck) 41 29
                t 17 11      (ear) 60 3c
                u 15 0f      (eh) 26 1a
                v 35 23      (er) 51 33
                w 46 2e      (err) 52 34
                y 49 31      (ng) 44 2c
                z 43 2b      (or) 58 3a
            (space) 1 01      (ou) 22 16
            (space) 3 03      (ouu) 31 1f
            (space) 4 04      (ow) 32 20
                                    (oy) 5 05
                                    (sh) 37 25
                                    (th) 29 1d
                                    (dth) 18 12
                                    (uh) 30 1e
                                    (wh) 48 30
                                    (zh) 33 21
*/
        public static void say(final String out){
            System.out.println("Saying:" + out);
            Speech = new Thread() {
            public void run() {
                talk=new Talker();
            talk.sayPhoneWord(out);
            }};
            Speech.start();
    }

}


Example:
|SAY,"hello world"

sends:
input:1B 07 2D 35 01 2E 3A 2D 15 00
to port &fbfe
I translate it to:
Saying:h|e|l|oo|10ms|w|or|l|d|

For this I use a simple java speech synthesizer, which is sample based. (1 .AU audiofile for each phoneme)

The Amstrad SSA-1 Synthesizer should work in a similar way only that the port is &fbee here.

Of course, PITCH settings or other speech manipulating commands are not possible here, but it produces a simple speech output.
http://cpc-live.com/speechtest
When you put your ear on a hot stove, you can smell how stupid you are ...

Amstrad CPC games in your webbrowser

JavaCPC Desktop Full Release

Executioner

Quote from: Devilmarkus on 01:41, 05 January 10
I am not sure. I need the rom like the existing DK'Tronics speech rom, which contains the RSX commands and port output routines

Oh, I don't have that, didn't even know it existed. I'm pretty sure my SSA-1 didn't have a ROM in it.

Executioner

Quote from: Devilmarkus on 01:41, 05 January 10
Here's how I emulate the DK'Tronics speech:

I thought you might be emulating the SPO256 using sound snips, but that doesn't allow for changes in pitch etc either. The only way to do it properly is to emulate the chip which is quite difficult and processor intensive.

nocash

#5
It should NOT be much more processor intensive than emulating the 3-channel PSG. It's a bit difficult though. Btw. I've just added some fairly complete SP0256 specs to the SSA-1 and Dk'tronics speech cpcwiki pages.

Properly emulating it is still impossible because the clock frequency used in the CPC interfaces is still unknown. Does somebody know more on that subject?

The SSA-1 seems to use a fixed clock frequency. Maybe the recommended 3.12MHz.

The Dk'tronics speech interface seems to allow to adjust the clock frequency (with the |SPED command), allowing to change the intonation. So this one is much more difficult, there must be an additional some I/O port (or additional bits in the known I/O port), and there seems to be no info on the selectable frequency range.

nocash

Judging from SSA-1 cpcwiki page, the RSX commands were included on cassette, not on ROM. No idea where to get the cassette from. Anyways, the games that do support it don't need the RSX commands and access the I/O port directly.

Btw. does somebody have RSX driver disk for the Dk'tronics speech interface? For this one, a ROM does actually exist (at ftp://ftp.nvg.ntnu.no/pub/cpc/emulator/rom/), but there should be also a RSX driver disk for the ROM-less version of that interface.

The disk version would be a bit easier to use, to figure out how the |SPED command works. The only known Dk'tronic speech game (Jumpjet) doesn't seem to use the SPED feature, so one could only rev-engineer the RSX driver.

CPCIak

#7
Here it is: http://share.cpcwiki.eu/931240

Well, it's not the ROM version. I've uploaded the *.cdt image including the manual.
According to the wiki the device was available on tape only!

CPCIak

Quote from: nocash on 05:06, 05 January 10Btw. does somebody have RSX driver disk for the Dk'tronics speech interface? For this one, a ROM does actually exist (at ftp://ftp.nvg.ntnu.no/pub/cpc/emulator/rom/), but there should be also a RSX driver disk for the ROM-less version of that interface.

Here we go: http://share.cpcwiki.eu/317082

Bryce

Excellent work Markus, I compared it to my real DKTronics Speech Synthesiser with the same sentences and it was spot on. I have the ROM based CPC464 version here and the original documentation, so let me know if there's any hardware or other info you need and I can pass it on to you.

Bryce.

Devilmarkus

Thanks... The CDT files for the Amstrad SSA-1 I know and already have.
I suggested that there would also exist a ROM file...

@ Bryce:
I am wondering that JavaCPC sounds so real.
It's a very basic Speech synthesizer which I found in web.
I only read out the port &FBFE and convert the bytes to phonemes.
These phonemes are set together to a phoneme string, which is send over the Speech synth.
No chip is emulated!

I know, that Kevin is working on this, too, and maybe he can emulate the chip, too...

To the users from DK'Tronics AND!!! Amstrad SSA-1:

Please do this from BASIC:
PRINT INP(&FBFE) -> DK'Tronics
PRINT INP(&FBEE) -> Amstrad SSA-1

I need booth return values (defaut is &FF when no speech device is connected, DK'Tronics should return &00 I think)
When you put your ear on a hot stove, you can smell how stupid you are ...

Amstrad CPC games in your webbrowser

JavaCPC Desktop Full Release

Gryzor

Well, if need be, I can send my SSA set. I can't dump it myself, but I'd be glad to lend it or even donate it (if it should be vandalized) for the good of science!

Devilmarkus

Please do this from BASIC when SSA-1 is connected:
PRINT INP(&FBEE)
Also do this while speaking...
I need the returned port value
Thank you.
When you put your ear on a hot stove, you can smell how stupid you are ...

Amstrad CPC games in your webbrowser

JavaCPC Desktop Full Release

nocash

> PRINT INP(&FBEE)
The I/O Ports are described in Appendix B and C of the SSA-1 manual.

The only thing that is unknown about the SSA-1 is the clock frequency.

Can somebody open it and check if it has a 3.12MHz oscillator, or something else?

nocash

Btw. does somebody know anything about the "MHT Speech Synthesizer"?
Does it exist? Does it use a SP0256, too? At what I/O ports? Is there any software for it? Etc.

Grim

Quote from: nocash on 15:23, 05 January 10
Can somebody open it and check if it has a 3.12MHz oscillator, or something else?
I found this (not that good) picture of the SSA-1 board if it can help somehow:

Devilmarkus

The question is: Do we really need a ROM?
When I have speech feature enabled, I can also enter this small listing in BASIC:
10 CLS
20 READ a$
30 IF a$="xx" THEN END
40 OUT &FBFE,VAL("&"+a$)
50 GOTO 20
60 DATA 00,00,01,21,13,01,01,02,2A,14,01
70 DATA 01,02,0D,27,18,0B,0C,08,37,01,01
80 DATA 37,09,13,32,01,01,37,31,0B,1D,07
90 DATA 37,06,2B,34,00,xx


This proggy says "DK'Tronics speech synthesizer" also when I have no Speech-rom set.
(For Amstrad SSA-1 you should change port number &FBFE in line 40 to &FBEE)

I don't know, if this would work with real hardware, too...
Maybe someone can test this?

I looked at appendix B but I don't understand these things :(
For that more emulation is needed, but I want to keep it simple.

I need to know the real value which is returned from port &FBEE...
When you put your ear on a hot stove, you can smell how stupid you are ...

Amstrad CPC games in your webbrowser

JavaCPC Desktop Full Release

Devilmarkus

SSA-1 reads booth ports:
FBFE and FFEE!
So I need booth values.
When you put your ear on a hot stove, you can smell how stupid you are ...

Amstrad CPC games in your webbrowser

JavaCPC Desktop Full Release

Bryce

Hi Markus,
         just pulled my DKTronics speech Synthesiser out from under the pile of CPC stuff, dusted it off and tried the Print INP(&FBFE) command... It returns the value 127. Hope this helps you further.

Bryce.

Devilmarkus

Yeah... This is the same than Amstrad SSI-1 does.
But:
SSI-1 changes port value to 0 in most cases when speech is spoken.
I don't know exactly yet how this works...
Please check the DK'Tronics, too, if it returns 0, while talking...

Here's a first SSA-1 test: http://cpc.devilmarkus.de/ssa1test

The Soccer game works well... also 3d Stuntrider.
I can also init speech,
but I cannot use |SAY command and also "Roland in space" still denies speech... :(
When you put your ear on a hot stove, you can smell how stupid you are ...

Amstrad CPC games in your webbrowser

JavaCPC Desktop Full Release

Devilmarkus

When you put your ear on a hot stove, you can smell how stupid you are ...

Amstrad CPC games in your webbrowser

JavaCPC Desktop Full Release

nocash

> I found this (not that good) picture of the SSA-1 board
Yeah, I know that image. The orange thing in the middle looks like an oscillator. But the resolution of the picture is too bad to read the part number printed on it.
Can somebody make a better photo?

> just pulled my DKTronics speech Synthesiser out from
> under the pile of CPC stuff, dusted it off
Photo of it's mainboard would be nice, too! Do you have a camera?

> dusted it off and tried the Print INP(&FBFE) command...
> It returns the value 127
No surprise so far. It would be interesting to see what happens when it is busy. Can you enter this line:
  OUT &FBFE,&04:PRINT INP (&FBFE)
that should a long output "OY" sound, and bit7 should get set... and maybe other bits change, too. So it may return 255... or something else.

> The question is: Do we really need a ROM?
No.

> 20 READ a$
> 30 IF a$="xx" THEN END
> 40 OUT &FBFE,VAL("&"+a$)
> 50 GOTO 20
You need to add a wait for stat bit7=0 in line 35:
  35 IF ((INP &FBFE) AND &80)>0 THEN 35
That bit is probably the /LRQ signal... or maybe the inverted SBY signal.
Not sure if the Dk'tronics outputs both /LRQ and SBY signals?

> I looked at appendix B but I don't understand these things
How is that possible? Where's the problem? Bit7 means 128, Bit6 means 64 - in case you haven't read your binary numbers tutorial recently.

As explained in Appendix C, with "/LOAD" they mean the /LRQ pin (Load Request), and with "/BUSY" they mean the SBY pin (Standby).

/LRQ=0 means it is ready to receive data (and may - or may not - be speeking)
SBY=1  means it is ready to receive data (and that is NOT speeking)

> SSA-1 reads booth ports:
> FBFE and FFEE!
Huh? What are you talking about here? I thought the SSA-1 is the hardware? If you are still talking of the status registers: The SSA-1 output status info on Port FBEE. I am sure it doesn't READ status info. And as far as I know it doesn't use Ports FBFE nor FFEE, only FBEE.

> SSI-1 changes port value to 0 in most cases when speech is spoken.
Really? Since bit0-5 are unused, I'd think that they are always high-z. And only bit7 and bit6 can go zero.

Bryce

Hi all,
        I can tell you what happens on a real DKTronics....

While it's speaking &FBFE is toggling between 255 and 127 (127 seems to be each time a pause is between letters)

And according to the SPO256 datasheet, the chip won't run with anything other than a 3.12MHz crystal, it's osc1 and osc2 inputs aren't configurable that you could control them any other way. Unless they used some old Gem such as Stateks PXO Series (a crystal in a chip which as far as I can remember could be varied to 64 different frequencies using a 6bit parallel input port and even be switched on and off) there will have to be a crystal in the box.

Bryce.

Cholo

Quote from: Bryce on 19:55, 05 January 10
Hi Markus,
         just pulled my DKTronics speech Synthesiser out from under the pile of CPC stuff, dusted it off and tried the Print INP(&FBFE) command... It returns the value 127. Hope this helps you further.

Bryce.
Well, just dug up a old DKTronics cart too (alas no speakers or software so i got it nearly for free). According to the manual its a Edition 2. Opening up the cart it also says v2 on the mobo. I dont think there is any "rom-software" on the mobo as there is pretty much only the SPO256A-AL2 chip. Manual also confirms that all commands need to be loaded from tape to be able to use them. The cart casing says "dk´tronics" on top.
Using the Print INP(&FBFE) i get 127 just like Bryce  :)
Using the OUT &FBFE,&04:PRINT INP (&FBFE) i get 127 again (didnt hear a "OY" sound tho?).

A bit off track: i recall seeing a different dktronics speech cart that said "dk'tronics speech rom" on top. So perhaps there are several versions, with and without rom software?

Even more off track: I recall the free speech software on with AA issue 103 (tape 37) uses the |say command but cant find this in the Dk´tronics manual.

Devilmarkus

OUT &FBFE,&04 causes a pause... So you can't hear it.
try OUT &FBFE,&05 instead ("OY")
When you put your ear on a hot stove, you can smell how stupid you are ...

Amstrad CPC games in your webbrowser

JavaCPC Desktop Full Release

Powered by SMFPacks Menu Editor Mod