Latest commit

History

145 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

SAM

Software Automatic Mouth - Tiny Speech Synthesizer

What is SAM?

Sam is a very small Text-To-Speech (TTS) program written in C, that runs on most popular platforms. It is an adaption to C of the speech software SAM (Software Automatic Mouth) for the Commodore C64 published in the year 1982 by Don't Ask Software (now SoftVoice, Inc.). It includes a Text-To-Phoneme converter called reciter and a Phoneme-To-Speech routine for the final output. It is so small that it will work also on embedded computers. On my computer it takes less than 39KB (much smaller on embedded devices as the executable-overhead is not necessary) of disk space and is a fully stand alone program. For immediate output it uses the SDL-library, otherwise it can save .wav files.

An online version and executables for Windows can be found on the web site: http://simulationcorner.net/index.php?page=sam

Compile

Simply type "make" in your command prompt. In order to compile without SDL remove the SDL statements from the CFLAGS and LFLAGS variables in the file "Makefile".

It should compile on every UNIX-like operating system. For Windows you need Cygwin or MinGW( + libsdl).

Usage

type

./sam I am Sam

for the first output.

If you have disabled SDL try

./sam -wav i_am_sam.wav I am Sam

to get a wav file. This file can be played by many media players available for the PC.

you can try other options like -pitch number -speed number -throat number -mouth number

Some typical values written in the original manual are:

DESCRIPTION SPEED PITCH THROAT MOUTH
Elf 72 64 110 160
Little Robot 92 60 190 190
Stuffy Guy 82 72 110 105
Little Old Lady 82 32 145 145
Extra-Terrestrial 100 64 150 200
SAM 72 64 128 128

It can even sing look at the file "sing" for a small example.

For the phoneme input table look in the Wiki.

A description of additional features can be found in the original manual at http://www.retrobits.net/atari/sam.shtml or in the manual of the equivalent Apple II program http://www.apple-iigs.info/newdoc/sam.pdf

Adaption To C

This program was converted semi-automatic into C by converting each assembler opcode. e. g.

lda 56 =>	A = mem[56];
jmp 38018 =>	goto pos38018;
inc 38 =>	mem[38]++;
. .
. .

Then it was manually rewritten to remove most of the jumps and register variables in the code and rename the variables to proper names. Most of the description below is a result of this rewriting process.

Unfortunately its still a not very good readable. But you should see where I started :)

Short description

First of all I will limit myself here to a very coarse description. There are very many exceptions defined in the source code that I will not explain. Also a lot of code is unknown for me e. g. Code47503. For a complete understanding of the code I need more time and especially more eyes have a look on the code.

Reciter

It changes the english text to phonemes by a ruleset shown in the wiki.

The rule " ANT(I)", "AY", means that if he find an "I" with previous letters " ANT", exchange the I by the phoneme "AY".

There are some special signs in this rules like # & @ ^ + : % which can mean e. g. that there must be a vocal or a consonant or something else.

With the -debug option you will get the corresponding rules and the resulting phonemes.

Output

Here is the full tree of subroutine calls:

SAMMain() Parser1() Parser2() Insert() CopyStress() SetPhonemeLength() Code48619() Code41240() Insert() Code48431() Insert()

Code48547
Code47574
Special1
Code47503
Code48227

SAMMain() is the entry routine and calls all further routines. Parser1 transforms the phoneme input and transforms it to three tables phonemeindex[] stress[] phonemelength[] (zero at this moment)

This tables are now changed:

Parser2 exchanges some phonemes by others and inserts new. CopyStress adds 1 to the stress under some circumstances SetPhonemeLength sets phoneme lengths. Code48619 changes the phoneme lengths Code41240 adds some additional phonemes Code48431 has some extra rules

The wiki shows all possible phonemes and some flag fields.
The final content of these tables can be seen with the -debug command.

In the function PrepareOutput() these tables are partly copied into the small tables: phonemeindexOutput[] stressOutput[] phonemelengthOutput[] for output.

Final Output

Except of some special phonemes the output is build by a linear combination:

A = A1 * sin ( f1 * t ) +
A2 * sin ( f2 * t ) +
A3 * rect( f3 * t )

where rect is a rectangular function with the same periodicity like sin. It seems really strange, but this is really enough for most types of phonemes.

Therefore the above phonemes are converted with some tables to pitches[] frequency1[] = f1 frequency2[] = f2 frequency3[] = f3 amplitude1[] = A1 amplitude2[] = A2 amplitude3[] = A3

Above formula is calculated in one very good omptimized routine. It only consist of 26 commands:

48087: LDX 43 ; get phase CLC LDA 42240,x	; load sine value (high 4 bits)
ORA TabAmpl1,y	; get amplitude (in low 4 bits)
TAX LDA 42752,x	; multiplication table
STA 56 ; store LDX 42 ; get phase
LDA 42240,x	; load sine value (high 4 bits)
ORA TabAmpl2,y	; get amplitude (in low 4 bits)
TAX LDA 42752,x	; multiplication table
ADC Var56	; add with previous values
STA 56 ; and store
LDX 41 ; get phase
LDA 42496,x	; load rect value (high 4 bits)
ORA TabAmpl3,y	; get amplitude (in low 4 bits)
TAX LDA 42752,x	; multiplication table
ADC 56 ; add with previous values
ADC #136 LSR A ; get highest 4 bits
LSR A LSR A LSR A STA 54296	;SID main output command

The rest is handled in a special way. At the moment I cannot figure out in which way. But it seems that it uses some noise (e. g. for "s") using a table with random values.

License

The software is a reverse-engineered version of a commercial software published more than 30 years ago. The current copyright holder is SoftVoice, Inc. (www.text2speech.com)

Any attempt to contact the company failed. The website was last updated in the year 2009. The status of the original software can therefore best described as Abandonware (http://en.wikipedia.org/wiki/Abandonware)

As long this is the case I cannot put my code under any specific open source software license Use it at your own risk.

Contact

If you have questions don' t hesitate to ask me. If you discovered some new knowledge about the code please mail me.

Sebastian Macke Email: sebastian@macke.de

About

Software Automatic Mouth - Tiny Speech Synthesizer

Resources

Stars

300 stars

Watchers

15 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Latest commit

History

145 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

SAM

Software Automatic Mouth - Tiny Speech Synthesizer

What is SAM?

Sam is a very small Text-To-Speech (TTS) program written in C, that runs on most popular platforms. It is an adaption to C of the speech software SAM (Software Automatic Mouth) for the Commodore C64 published in the year 1982 by Don't Ask Software (now SoftVoice, Inc.). It includes a Text-To-Phoneme converter called reciter and a Phoneme-To-Speech routine for the final output. It is so small that it will work also on embedded computers. On my computer it takes less than 39KB (much smaller on embedded devices as the executable-overhead is not necessary) of disk space and is a fully stand alone program. For immediate output it uses the SDL-library, otherwise it can save .wav files.

An online version and executables for Windows can be found on the web site: http://simulationcorner.net/index.php?page=sam

Compile

Simply type "make" in your command prompt. In order to compile without SDL remove the SDL statements from the CFLAGS and LFLAGS variables in the file "Makefile".

It should compile on every UNIX-like operating system. For Windows you need Cygwin or MinGW( + libsdl).

Usage

type

./sam I am Sam

for the first output.

If you have disabled SDL try

./sam -wav i_am_sam.wav I am Sam

to get a wav file. This file can be played by many media players available for the PC.

you can try other options like -pitch number -speed number -throat number -mouth number

Some typical values written in the original manual are:

DESCRIPTION SPEED PITCH THROAT MOUTH
Elf 72 64 110 160
Little Robot 92 60 190 190
Stuffy Guy 82 72 110 105
Little Old Lady 82 32 145 145
Extra-Terrestrial 100 64 150 200
SAM 72 64 128 128

It can even sing look at the file "sing" for a small example.

For the phoneme input table look in the Wiki.

A description of additional features can be found in the original manual at http://www.retrobits.net/atari/sam.shtml or in the manual of the equivalent Apple II program http://www.apple-iigs.info/newdoc/sam.pdf

Adaption To C

This program was converted semi-automatic into C by converting each assembler opcode. e. g.

lda 56 =>	A = mem[56];
jmp 38018 =>	goto pos38018;
inc 38 =>	mem[38]++;
. .
. .

Then it was manually rewritten to remove most of the jumps and register variables in the code and rename the variables to proper names. Most of the description below is a result of this rewriting process.

Unfortunately its still a not very good readable. But you should see where I started :)

Short description

First of all I will limit myself here to a very coarse description. There are very many exceptions defined in the source code that I will not explain. Also a lot of code is unknown for me e. g. Code47503. For a complete understanding of the code I need more time and especially more eyes have a look on the code.

Reciter

It changes the english text to phonemes by a ruleset shown in the wiki.

The rule " ANT(I)", "AY", means that if he find an "I" with previous letters " ANT", exchange the I by the phoneme "AY".

There are some special signs in this rules like # & @ ^ + : % which can mean e. g. that there must be a vocal or a consonant or something else.

With the -debug option you will get the corresponding rules and the resulting phonemes.

Output

Here is the full tree of subroutine calls:

SAMMain() Parser1() Parser2() Insert() CopyStress() SetPhonemeLength() Code48619() Code41240() Insert() Code48431() Insert()

Code48547
Code47574
Special1
Code47503
Code48227

SAMMain() is the entry routine and calls all further routines. Parser1 transforms the phoneme input and transforms it to three tables phonemeindex[] stress[] phonemelength[] (zero at this moment)

This tables are now changed:

Parser2 exchanges some phonemes by others and inserts new. CopyStress adds 1 to the stress under some circumstances SetPhonemeLength sets phoneme lengths. Code48619 changes the phoneme lengths Code41240 adds some additional phonemes Code48431 has some extra rules

The wiki shows all possible phonemes and some flag fields.
The final content of these tables can be seen with the -debug command.

In the function PrepareOutput() these tables are partly copied into the small tables: phonemeindexOutput[] stressOutput[] phonemelengthOutput[] for output.

Final Output

Except of some special phonemes the output is build by a linear combination:

A = A1 * sin ( f1 * t ) +
A2 * sin ( f2 * t ) +
A3 * rect( f3 * t )

where rect is a rectangular function with the same periodicity like sin. It seems really strange, but this is really enough for most types of phonemes.

Therefore the above phonemes are converted with some tables to pitches[] frequency1[] = f1 frequency2[] = f2 frequency3[] = f3 amplitude1[] = A1 amplitude2[] = A2 amplitude3[] = A3

Above formula is calculated in one very good omptimized routine. It only consist of 26 commands:

48087: LDX 43 ; get phase CLC LDA 42240,x	; load sine value (high 4 bits)
ORA TabAmpl1,y	; get amplitude (in low 4 bits)
TAX LDA 42752,x	; multiplication table
STA 56 ; store LDX 42 ; get phase
LDA 42240,x	; load sine value (high 4 bits)
ORA TabAmpl2,y	; get amplitude (in low 4 bits)
TAX LDA 42752,x	; multiplication table
ADC Var56	; add with previous values
STA 56 ; and store
LDX 41 ; get phase
LDA 42496,x	; load rect value (high 4 bits)
ORA TabAmpl3,y	; get amplitude (in low 4 bits)
TAX LDA 42752,x	; multiplication table
ADC 56 ; add with previous values
ADC #136 LSR A ; get highest 4 bits
LSR A LSR A LSR A STA 54296	;SID main output command

The rest is handled in a special way. At the moment I cannot figure out in which way. But it seems that it uses some noise (e. g. for "s") using a table with random values.

License

The software is a reverse-engineered version of a commercial software published more than 30 years ago. The current copyright holder is SoftVoice, Inc. (www.text2speech.com)

Any attempt to contact the company failed. The website was last updated in the year 2009. The status of the original software can therefore best described as Abandonware (http://en.wikipedia.org/wiki/Abandonware)

As long this is the case I cannot put my code under any specific open source software license Use it at your own risk.

Contact

If you have questions don' t hesitate to ask me. If you discovered some new knowledge about the code please mail me.

Sebastian Macke Email: sebastian@macke.de

About

Software Automatic Mouth - Tiny Speech Synthesizer

Resources

Stars

300 stars

Watchers

15 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

145 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

SAM

Software Automatic Mouth - Tiny Speech Synthesizer

What is SAM?

Sam is a very small Text-To-Speech (TTS) program written in C, that runs on most popular platforms. It is an adaption to C of the speech software SAM (Software Automatic Mouth) for the Commodore C64 published in the year 1982 by Don't Ask Software (now SoftVoice, Inc.). It includes a Text-To-Phoneme converter called reciter and a Phoneme-To-Speech routine for the final output. It is so small that it will work also on embedded computers. On my computer it takes less than 39KB (much smaller on embedded devices as the executable-overhead is not necessary) of disk space and is a fully stand alone program. For immediate output it uses the SDL-library, otherwise it can save .wav files.

An online version and executables for Windows can be found on the web site: http://simulationcorner.net/index.php?page=sam

Compile

Simply type "make" in your command prompt. In order to compile without SDL remove the SDL statements from the CFLAGS and LFLAGS variables in the file "Makefile".

It should compile on every UNIX-like operating system. For Windows you need Cygwin or MinGW( + libsdl).

Usage

type

./sam I am Sam

for the first output.

If you have disabled SDL try

./sam -wav i_am_sam.wav I am Sam

to get a wav file. This file can be played by many media players available for the PC.

you can try other options like -pitch number -speed number -throat number -mouth number

Some typical values written in the original manual are:

DESCRIPTION SPEED PITCH THROAT MOUTH
Elf 72 64 110 160
Little Robot 92 60 190 190
Stuffy Guy 82 72 110 105
Little Old Lady 82 32 145 145
Extra-Terrestrial 100 64 150 200
SAM 72 64 128 128

It can even sing look at the file "sing" for a small example.

For the phoneme input table look in the Wiki.

A description of additional features can be found in the original manual at http://www.retrobits.net/atari/sam.shtml or in the manual of the equivalent Apple II program http://www.apple-iigs.info/newdoc/sam.pdf

Adaption To C

This program was converted semi-automatic into C by converting each assembler opcode. e. g.

lda 56 =>	A = mem[56];
jmp 38018 =>	goto pos38018;
inc 38 =>	mem[38]++;
. .
. .

Then it was manually rewritten to remove most of the jumps and register variables in the code and rename the variables to proper names. Most of the description below is a result of this rewriting process.

Unfortunately its still a not very good readable. But you should see where I started :)

Short description

First of all I will limit myself here to a very coarse description. There are very many exceptions defined in the source code that I will not explain. Also a lot of code is unknown for me e. g. Code47503. For a complete understanding of the code I need more time and especially more eyes have a look on the code.

Reciter

It changes the english text to phonemes by a ruleset shown in the wiki.

The rule " ANT(I)", "AY", means that if he find an "I" with previous letters " ANT", exchange the I by the phoneme "AY".

There are some special signs in this rules like # & @ ^ + : % which can mean e. g. that there must be a vocal or a consonant or something else.

With the -debug option you will get the corresponding rules and the resulting phonemes.

Output

Here is the full tree of subroutine calls:

SAMMain() Parser1() Parser2() Insert() CopyStress() SetPhonemeLength() Code48619() Code41240() Insert() Code48431() Insert()

Code48547
Code47574
Special1
Code47503
Code48227

SAMMain() is the entry routine and calls all further routines. Parser1 transforms the phoneme input and transforms it to three tables phonemeindex[] stress[] phonemelength[] (zero at this moment)

This tables are now changed:

Parser2 exchanges some phonemes by others and inserts new. CopyStress adds 1 to the stress under some circumstances SetPhonemeLength sets phoneme lengths. Code48619 changes the phoneme lengths Code41240 adds some additional phonemes Code48431 has some extra rules

The wiki shows all possible phonemes and some flag fields.
The final content of these tables can be seen with the -debug command.

In the function PrepareOutput() these tables are partly copied into the small tables: phonemeindexOutput[] stressOutput[] phonemelengthOutput[] for output.

Final Output

Except of some special phonemes the output is build by a linear combination:

A = A1 * sin ( f1 * t ) +
A2 * sin ( f2 * t ) +
A3 * rect( f3 * t )

where rect is a rectangular function with the same periodicity like sin. It seems really strange, but this is really enough for most types of phonemes.

Therefore the above phonemes are converted with some tables to pitches[] frequency1[] = f1 frequency2[] = f2 frequency3[] = f3 amplitude1[] = A1 amplitude2[] = A2 amplitude3[] = A3

Above formula is calculated in one very good omptimized routine. It only consist of 26 commands:

48087: LDX 43 ; get phase CLC LDA 42240,x	; load sine value (high 4 bits)
ORA TabAmpl1,y	; get amplitude (in low 4 bits)
TAX LDA 42752,x	; multiplication table
STA 56 ; store LDX 42 ; get phase
LDA 42240,x	; load sine value (high 4 bits)
ORA TabAmpl2,y	; get amplitude (in low 4 bits)
TAX LDA 42752,x	; multiplication table
ADC Var56	; add with previous values
STA 56 ; and store
LDX 41 ; get phase
LDA 42496,x	; load rect value (high 4 bits)
ORA TabAmpl3,y	; get amplitude (in low 4 bits)
TAX LDA 42752,x	; multiplication table
ADC 56 ; add with previous values
ADC #136 LSR A ; get highest 4 bits
LSR A LSR A LSR A STA 54296	;SID main output command

The rest is handled in a special way. At the moment I cannot figure out in which way. But it seems that it uses some noise (e. g. for "s") using a table with random values.

License

The software is a reverse-engineered version of a commercial software published more than 30 years ago. The current copyright holder is SoftVoice, Inc. (www.text2speech.com)

Any attempt to contact the company failed. The website was last updated in the year 2009. The status of the original software can therefore best described as Abandonware (http://en.wikipedia.org/wiki/Abandonware)

As long this is the case I cannot put my code under any specific open source software license Use it at your own risk.

Contact

If you have questions don' t hesitate to ask me. If you discovered some new knowledge about the code please mail me.

Sebastian Macke Email: sebastian@macke.de

About

Software Automatic Mouth - Tiny Speech Synthesizer

Resources

Stars

300 stars

Watchers

15 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

145 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

SAM

Software Automatic Mouth - Tiny Speech Synthesizer

What is SAM?

Sam is a very small Text-To-Speech (TTS) program written in C, that runs on most popular platforms. It is an adaption to C of the speech software SAM (Software Automatic Mouth) for the Commodore C64 published in the year 1982 by Don't Ask Software (now SoftVoice, Inc.). It includes a Text-To-Phoneme converter called reciter and a Phoneme-To-Speech routine for the final output. It is so small that it will work also on embedded computers. On my computer it takes less than 39KB (much smaller on embedded devices as the executable-overhead is not necessary) of disk space and is a fully stand alone program. For immediate output it uses the SDL-library, otherwise it can save .wav files.

An online version and executables for Windows can be found on the web site: http://simulationcorner.net/index.php?page=sam

Compile

Simply type "make" in your command prompt. In order to compile without SDL remove the SDL statements from the CFLAGS and LFLAGS variables in the file "Makefile".

It should compile on every UNIX-like operating system. For Windows you need Cygwin or MinGW( + libsdl).

Usage

type

./sam I am Sam

for the first output.

If you have disabled SDL try

./sam -wav i_am_sam.wav I am Sam

to get a wav file. This file can be played by many media players available for the PC.

you can try other options like -pitch number -speed number -throat number -mouth number

Some typical values written in the original manual are:

DESCRIPTION SPEED PITCH THROAT MOUTH
Elf 72 64 110 160
Little Robot 92 60 190 190
Stuffy Guy 82 72 110 105
Little Old Lady 82 32 145 145
Extra-Terrestrial 100 64 150 200
SAM 72 64 128 128

It can even sing look at the file "sing" for a small example.

For the phoneme input table look in the Wiki.

A description of additional features can be found in the original manual at http://www.retrobits.net/atari/sam.shtml or in the manual of the equivalent Apple II program http://www.apple-iigs.info/newdoc/sam.pdf

Adaption To C

This program was converted semi-automatic into C by converting each assembler opcode. e. g.

lda 56 =>	A = mem[56];
jmp 38018 =>	goto pos38018;
inc 38 =>	mem[38]++;
. .
. .

Then it was manually rewritten to remove most of the jumps and register variables in the code and rename the variables to proper names. Most of the description below is a result of this rewriting process.

Unfortunately its still a not very good readable. But you should see where I started :)

Short description

First of all I will limit myself here to a very coarse description. There are very many exceptions defined in the source code that I will not explain. Also a lot of code is unknown for me e. g. Code47503. For a complete understanding of the code I need more time and especially more eyes have a look on the code.

Reciter

It changes the english text to phonemes by a ruleset shown in the wiki.

The rule " ANT(I)", "AY", means that if he find an "I" with previous letters " ANT", exchange the I by the phoneme "AY".

There are some special signs in this rules like # & @ ^ + : % which can mean e. g. that there must be a vocal or a consonant or something else.

With the -debug option you will get the corresponding rules and the resulting phonemes.

Output

Here is the full tree of subroutine calls:

SAMMain() Parser1() Parser2() Insert() CopyStress() SetPhonemeLength() Code48619() Code41240() Insert() Code48431() Insert()

Code48547
Code47574
Special1
Code47503
Code48227

SAMMain() is the entry routine and calls all further routines. Parser1 transforms the phoneme input and transforms it to three tables phonemeindex[] stress[] phonemelength[] (zero at this moment)

This tables are now changed:

Parser2 exchanges some phonemes by others and inserts new. CopyStress adds 1 to the stress under some circumstances SetPhonemeLength sets phoneme lengths. Code48619 changes the phoneme lengths Code41240 adds some additional phonemes Code48431 has some extra rules

The wiki shows all possible phonemes and some flag fields.
The final content of these tables can be seen with the -debug command.

In the function PrepareOutput() these tables are partly copied into the small tables: phonemeindexOutput[] stressOutput[] phonemelengthOutput[] for output.

Final Output

Except of some special phonemes the output is build by a linear combination:

A = A1 * sin ( f1 * t ) +
A2 * sin ( f2 * t ) +
A3 * rect( f3 * t )

where rect is a rectangular function with the same periodicity like sin. It seems really strange, but this is really enough for most types of phonemes.

Therefore the above phonemes are converted with some tables to pitches[] frequency1[] = f1 frequency2[] = f2 frequency3[] = f3 amplitude1[] = A1 amplitude2[] = A2 amplitude3[] = A3

Above formula is calculated in one very good omptimized routine. It only consist of 26 commands:

48087: LDX 43 ; get phase CLC LDA 42240,x	; load sine value (high 4 bits)
ORA TabAmpl1,y	; get amplitude (in low 4 bits)
TAX LDA 42752,x	; multiplication table
STA 56 ; store LDX 42 ; get phase
LDA 42240,x	; load sine value (high 4 bits)
ORA TabAmpl2,y	; get amplitude (in low 4 bits)
TAX LDA 42752,x	; multiplication table
ADC Var56	; add with previous values
STA 56 ; and store
LDX 41 ; get phase
LDA 42496,x	; load rect value (high 4 bits)
ORA TabAmpl3,y	; get amplitude (in low 4 bits)
TAX LDA 42752,x	; multiplication table
ADC 56 ; add with previous values
ADC #136 LSR A ; get highest 4 bits
LSR A LSR A LSR A STA 54296	;SID main output command

The rest is handled in a special way. At the moment I cannot figure out in which way. But it seems that it uses some noise (e. g. for "s") using a table with random values.

License

The software is a reverse-engineered version of a commercial software published more than 30 years ago. The current copyright holder is SoftVoice, Inc. (www.text2speech.com)

Any attempt to contact the company failed. The website was last updated in the year 2009. The status of the original software can therefore best described as Abandonware (http://en.wikipedia.org/wiki/Abandonware)

As long this is the case I cannot put my code under any specific open source software license Use it at your own risk.

Contact

If you have questions don' t hesitate to ask me. If you discovered some new knowledge about the code please mail me.

Sebastian Macke Email: sebastian@macke.de

About

Software Automatic Mouth - Tiny Speech Synthesizer

Resources

Stars

300 stars

Watchers

15 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Latest commit

History

145 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

SAM

Software Automatic Mouth - Tiny Speech Synthesizer

What is SAM?

Sam is a very small Text-To-Speech (TTS) program written in C, that runs on most popular platforms. It is an adaption to C of the speech software SAM (Software Automatic Mouth) for the Commodore C64 published in the year 1982 by Don't Ask Software (now SoftVoice, Inc.). It includes a Text-To-Phoneme converter called reciter and a Phoneme-To-Speech routine for the final output. It is so small that it will work also on embedded computers. On my computer it takes less than 39KB (much smaller on embedded devices as the executable-overhead is not necessary) of disk space and is a fully stand alone program. For immediate output it uses the SDL-library, otherwise it can save .wav files.

An online version and executables for Windows can be found on the web site: http://simulationcorner.net/index.php?page=sam

Compile

Simply type "make" in your command prompt. In order to compile without SDL remove the SDL statements from the CFLAGS and LFLAGS variables in the file "Makefile".

It should compile on every UNIX-like operating system. For Windows you need Cygwin or MinGW( + libsdl).

Usage

type

./sam I am Sam

for the first output.

If you have disabled SDL try

./sam -wav i_am_sam.wav I am Sam

to get a wav file. This file can be played by many media players available for the PC.

you can try other options like -pitch number -speed number -throat number -mouth number

Some typical values written in the original manual are:

DESCRIPTION SPEED PITCH THROAT MOUTH
Elf 72 64 110 160
Little Robot 92 60 190 190
Stuffy Guy 82 72 110 105
Little Old Lady 82 32 145 145
Extra-Terrestrial 100 64 150 200
SAM 72 64 128 128

It can even sing look at the file "sing" for a small example.

For the phoneme input table look in the Wiki.

A description of additional features can be found in the original manual at http://www.retrobits.net/atari/sam.shtml or in the manual of the equivalent Apple II program http://www.apple-iigs.info/newdoc/sam.pdf

Adaption To C

This program was converted semi-automatic into C by converting each assembler opcode. e. g.

lda 56 =>	A = mem[56];
jmp 38018 =>	goto pos38018;
inc 38 =>	mem[38]++;
. .
. .

Then it was manually rewritten to remove most of the jumps and register variables in the code and rename the variables to proper names. Most of the description below is a result of this rewriting process.

Unfortunately its still a not very good readable. But you should see where I started :)

Short description

First of all I will limit myself here to a very coarse description. There are very many exceptions defined in the source code that I will not explain. Also a lot of code is unknown for me e. g. Code47503. For a complete understanding of the code I need more time and especially more eyes have a look on the code.

Reciter

It changes the english text to phonemes by a ruleset shown in the wiki.

The rule " ANT(I)", "AY", means that if he find an "I" with previous letters " ANT", exchange the I by the phoneme "AY".

There are some special signs in this rules like # & @ ^ + : % which can mean e. g. that there must be a vocal or a consonant or something else.

With the -debug option you will get the corresponding rules and the resulting phonemes.

Output

Here is the full tree of subroutine calls:

SAMMain() Parser1() Parser2() Insert() CopyStress() SetPhonemeLength() Code48619() Code41240() Insert() Code48431() Insert()

Code48547
Code47574
Special1
Code47503
Code48227

SAMMain() is the entry routine and calls all further routines. Parser1 transforms the phoneme input and transforms it to three tables phonemeindex[] stress[] phonemelength[] (zero at this moment)

This tables are now changed:

Parser2 exchanges some phonemes by others and inserts new. CopyStress adds 1 to the stress under some circumstances SetPhonemeLength sets phoneme lengths. Code48619 changes the phoneme lengths Code41240 adds some additional phonemes Code48431 has some extra rules

The wiki shows all possible phonemes and some flag fields.
The final content of these tables can be seen with the -debug command.

In the function PrepareOutput() these tables are partly copied into the small tables: phonemeindexOutput[] stressOutput[] phonemelengthOutput[] for output.

Final Output

Except of some special phonemes the output is build by a linear combination:

A = A1 * sin ( f1 * t ) +
A2 * sin ( f2 * t ) +
A3 * rect( f3 * t )

where rect is a rectangular function with the same periodicity like sin. It seems really strange, but this is really enough for most types of phonemes.

Therefore the above phonemes are converted with some tables to pitches[] frequency1[] = f1 frequency2[] = f2 frequency3[] = f3 amplitude1[] = A1 amplitude2[] = A2 amplitude3[] = A3

Above formula is calculated in one very good omptimized routine. It only consist of 26 commands:

48087: LDX 43 ; get phase CLC LDA 42240,x	; load sine value (high 4 bits)
ORA TabAmpl1,y	; get amplitude (in low 4 bits)
TAX LDA 42752,x	; multiplication table
STA 56 ; store LDX 42 ; get phase
LDA 42240,x	; load sine value (high 4 bits)
ORA TabAmpl2,y	; get amplitude (in low 4 bits)
TAX LDA 42752,x	; multiplication table
ADC Var56	; add with previous values
STA 56 ; and store
LDX 41 ; get phase
LDA 42496,x	; load rect value (high 4 bits)
ORA TabAmpl3,y	; get amplitude (in low 4 bits)
TAX LDA 42752,x	; multiplication table
ADC 56 ; add with previous values
ADC #136 LSR A ; get highest 4 bits
LSR A LSR A LSR A STA 54296	;SID main output command

The rest is handled in a special way. At the moment I cannot figure out in which way. But it seems that it uses some noise (e. g. for "s") using a table with random values.

License

The software is a reverse-engineered version of a commercial software published more than 30 years ago. The current copyright holder is SoftVoice, Inc. (www.text2speech.com)

Any attempt to contact the company failed. The website was last updated in the year 2009. The status of the original software can therefore best described as Abandonware (http://en.wikipedia.org/wiki/Abandonware)

As long this is the case I cannot put my code under any specific open source software license Use it at your own risk.

Contact

If you have questions don' t hesitate to ask me. If you discovered some new knowledge about the code please mail me.

Sebastian Macke Email: sebastian@macke.de

About

Software Automatic Mouth - Tiny Speech Synthesizer

Resources

Stars

300 stars

Watchers

15 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

145 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

SAM

Software Automatic Mouth - Tiny Speech Synthesizer

What is SAM?

Sam is a very small Text-To-Speech (TTS) program written in C, that runs on most popular platforms. It is an adaption to C of the speech software SAM (Software Automatic Mouth) for the Commodore C64 published in the year 1982 by Don't Ask Software (now SoftVoice, Inc.). It includes a Text-To-Phoneme converter called reciter and a Phoneme-To-Speech routine for the final output. It is so small that it will work also on embedded computers. On my computer it takes less than 39KB (much smaller on embedded devices as the executable-overhead is not necessary) of disk space and is a fully stand alone program. For immediate output it uses the SDL-library, otherwise it can save .wav files.

An online version and executables for Windows can be found on the web site: http://simulationcorner.net/index.php?page=sam

Compile

Simply type "make" in your command prompt. In order to compile without SDL remove the SDL statements from the CFLAGS and LFLAGS variables in the file "Makefile".

It should compile on every UNIX-like operating system. For Windows you need Cygwin or MinGW( + libsdl).

Usage

type

./sam I am Sam

for the first output.

If you have disabled SDL try

./sam -wav i_am_sam.wav I am Sam

to get a wav file. This file can be played by many media players available for the PC.

you can try other options like -pitch number -speed number -throat number -mouth number

Some typical values written in the original manual are:

DESCRIPTION SPEED PITCH THROAT MOUTH
Elf 72 64 110 160
Little Robot 92 60 190 190
Stuffy Guy 82 72 110 105
Little Old Lady 82 32 145 145
Extra-Terrestrial 100 64 150 200
SAM 72 64 128 128

It can even sing look at the file "sing" for a small example.

For the phoneme input table look in the Wiki.

A description of additional features can be found in the original manual at http://www.retrobits.net/atari/sam.shtml or in the manual of the equivalent Apple II program http://www.apple-iigs.info/newdoc/sam.pdf

Adaption To C

This program was converted semi-automatic into C by converting each assembler opcode. e. g.

lda 56 =>	A = mem[56];
jmp 38018 =>	goto pos38018;
inc 38 =>	mem[38]++;
. .
. .

Then it was manually rewritten to remove most of the jumps and register variables in the code and rename the variables to proper names. Most of the description below is a result of this rewriting process.

Unfortunately its still a not very good readable. But you should see where I started :)

Short description

First of all I will limit myself here to a very coarse description. There are very many exceptions defined in the source code that I will not explain. Also a lot of code is unknown for me e. g. Code47503. For a complete understanding of the code I need more time and especially more eyes have a look on the code.

Reciter

It changes the english text to phonemes by a ruleset shown in the wiki.

The rule " ANT(I)", "AY", means that if he find an "I" with previous letters " ANT", exchange the I by the phoneme "AY".

There are some special signs in this rules like # & @ ^ + : % which can mean e. g. that there must be a vocal or a consonant or something else.

With the -debug option you will get the corresponding rules and the resulting phonemes.

Output

Here is the full tree of subroutine calls:

SAMMain() Parser1() Parser2() Insert() CopyStress() SetPhonemeLength() Code48619() Code41240() Insert() Code48431() Insert()

Code48547
Code47574
Special1
Code47503
Code48227

SAMMain() is the entry routine and calls all further routines. Parser1 transforms the phoneme input and transforms it to three tables phonemeindex[] stress[] phonemelength[] (zero at this moment)

This tables are now changed:

Parser2 exchanges some phonemes by others and inserts new. CopyStress adds 1 to the stress under some circumstances SetPhonemeLength sets phoneme lengths. Code48619 changes the phoneme lengths Code41240 adds some additional phonemes Code48431 has some extra rules

The wiki shows all possible phonemes and some flag fields.
The final content of these tables can be seen with the -debug command.

In the function PrepareOutput() these tables are partly copied into the small tables: phonemeindexOutput[] stressOutput[] phonemelengthOutput[] for output.

Final Output

Except of some special phonemes the output is build by a linear combination:

A = A1 * sin ( f1 * t ) +
A2 * sin ( f2 * t ) +
A3 * rect( f3 * t )

where rect is a rectangular function with the same periodicity like sin. It seems really strange, but this is really enough for most types of phonemes.

Therefore the above phonemes are converted with some tables to pitches[] frequency1[] = f1 frequency2[] = f2 frequency3[] = f3 amplitude1[] = A1 amplitude2[] = A2 amplitude3[] = A3

Above formula is calculated in one very good omptimized routine. It only consist of 26 commands:

48087: LDX 43 ; get phase CLC LDA 42240,x	; load sine value (high 4 bits)
ORA TabAmpl1,y	; get amplitude (in low 4 bits)
TAX LDA 42752,x	; multiplication table
STA 56 ; store LDX 42 ; get phase
LDA 42240,x	; load sine value (high 4 bits)
ORA TabAmpl2,y	; get amplitude (in low 4 bits)
TAX LDA 42752,x	; multiplication table
ADC Var56	; add with previous values
STA 56 ; and store
LDX 41 ; get phase
LDA 42496,x	; load rect value (high 4 bits)
ORA TabAmpl3,y	; get amplitude (in low 4 bits)
TAX LDA 42752,x	; multiplication table
ADC 56 ; add with previous values
ADC #136 LSR A ; get highest 4 bits
LSR A LSR A LSR A STA 54296	;SID main output command

The rest is handled in a special way. At the moment I cannot figure out in which way. But it seems that it uses some noise (e. g. for "s") using a table with random values.

License

The software is a reverse-engineered version of a commercial software published more than 30 years ago. The current copyright holder is SoftVoice, Inc. (www.text2speech.com)

Any attempt to contact the company failed. The website was last updated in the year 2009. The status of the original software can therefore best described as Abandonware (http://en.wikipedia.org/wiki/Abandonware)

As long this is the case I cannot put my code under any specific open source software license Use it at your own risk.

Contact

If you have questions don' t hesitate to ask me. If you discovered some new knowledge about the code please mail me.

Sebastian Macke Email: sebastian@macke.de

About

Software Automatic Mouth - Tiny Speech Synthesizer

Resources

Stars

300 stars

Watchers

15 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

145 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

SAM

Software Automatic Mouth - Tiny Speech Synthesizer

What is SAM?

Sam is a very small Text-To-Speech (TTS) program written in C, that runs on most popular platforms. It is an adaption to C of the speech software SAM (Software Automatic Mouth) for the Commodore C64 published in the year 1982 by Don't Ask Software (now SoftVoice, Inc.). It includes a Text-To-Phoneme converter called reciter and a Phoneme-To-Speech routine for the final output. It is so small that it will work also on embedded computers. On my computer it takes less than 39KB (much smaller on embedded devices as the executable-overhead is not necessary) of disk space and is a fully stand alone program. For immediate output it uses the SDL-library, otherwise it can save .wav files.

An online version and executables for Windows can be found on the web site: http://simulationcorner.net/index.php?page=sam

Compile

Simply type "make" in your command prompt. In order to compile without SDL remove the SDL statements from the CFLAGS and LFLAGS variables in the file "Makefile".

It should compile on every UNIX-like operating system. For Windows you need Cygwin or MinGW( + libsdl).

Usage

type

./sam I am Sam

for the first output.

If you have disabled SDL try

./sam -wav i_am_sam.wav I am Sam

to get a wav file. This file can be played by many media players available for the PC.

you can try other options like -pitch number -speed number -throat number -mouth number

Some typical values written in the original manual are:

DESCRIPTION SPEED PITCH THROAT MOUTH
Elf 72 64 110 160
Little Robot 92 60 190 190
Stuffy Guy 82 72 110 105
Little Old Lady 82 32 145 145
Extra-Terrestrial 100 64 150 200
SAM 72 64 128 128

It can even sing look at the file "sing" for a small example.

For the phoneme input table look in the Wiki.

A description of additional features can be found in the original manual at http://www.retrobits.net/atari/sam.shtml or in the manual of the equivalent Apple II program http://www.apple-iigs.info/newdoc/sam.pdf

Adaption To C

This program was converted semi-automatic into C by converting each assembler opcode. e. g.

lda 56 =>	A = mem[56];
jmp 38018 =>	goto pos38018;
inc 38 =>	mem[38]++;
. .
. .

Then it was manually rewritten to remove most of the jumps and register variables in the code and rename the variables to proper names. Most of the description below is a result of this rewriting process.

Unfortunately its still a not very good readable. But you should see where I started :)

Short description

First of all I will limit myself here to a very coarse description. There are very many exceptions defined in the source code that I will not explain. Also a lot of code is unknown for me e. g. Code47503. For a complete understanding of the code I need more time and especially more eyes have a look on the code.

Reciter

It changes the english text to phonemes by a ruleset shown in the wiki.

The rule " ANT(I)", "AY", means that if he find an "I" with previous letters " ANT", exchange the I by the phoneme "AY".

There are some special signs in this rules like # & @ ^ + : % which can mean e. g. that there must be a vocal or a consonant or something else.

With the -debug option you will get the corresponding rules and the resulting phonemes.

Output

Here is the full tree of subroutine calls:

SAMMain() Parser1() Parser2() Insert() CopyStress() SetPhonemeLength() Code48619() Code41240() Insert() Code48431() Insert()

Code48547
Code47574
Special1
Code47503
Code48227

SAMMain() is the entry routine and calls all further routines. Parser1 transforms the phoneme input and transforms it to three tables phonemeindex[] stress[] phonemelength[] (zero at this moment)

This tables are now changed:

Parser2 exchanges some phonemes by others and inserts new. CopyStress adds 1 to the stress under some circumstances SetPhonemeLength sets phoneme lengths. Code48619 changes the phoneme lengths Code41240 adds some additional phonemes Code48431 has some extra rules

The wiki shows all possible phonemes and some flag fields.
The final content of these tables can be seen with the -debug command.

In the function PrepareOutput() these tables are partly copied into the small tables: phonemeindexOutput[] stressOutput[] phonemelengthOutput[] for output.

Final Output

Except of some special phonemes the output is build by a linear combination:

A = A1 * sin ( f1 * t ) +
A2 * sin ( f2 * t ) +
A3 * rect( f3 * t )

where rect is a rectangular function with the same periodicity like sin. It seems really strange, but this is really enough for most types of phonemes.

Therefore the above phonemes are converted with some tables to pitches[] frequency1[] = f1 frequency2[] = f2 frequency3[] = f3 amplitude1[] = A1 amplitude2[] = A2 amplitude3[] = A3

Above formula is calculated in one very good omptimized routine. It only consist of 26 commands:

48087: LDX 43 ; get phase CLC LDA 42240,x	; load sine value (high 4 bits)
ORA TabAmpl1,y	; get amplitude (in low 4 bits)
TAX LDA 42752,x	; multiplication table
STA 56 ; store LDX 42 ; get phase
LDA 42240,x	; load sine value (high 4 bits)
ORA TabAmpl2,y	; get amplitude (in low 4 bits)
TAX LDA 42752,x	; multiplication table
ADC Var56	; add with previous values
STA 56 ; and store
LDX 41 ; get phase
LDA 42496,x	; load rect value (high 4 bits)
ORA TabAmpl3,y	; get amplitude (in low 4 bits)
TAX LDA 42752,x	; multiplication table
ADC 56 ; add with previous values
ADC #136 LSR A ; get highest 4 bits
LSR A LSR A LSR A STA 54296	;SID main output command

The rest is handled in a special way. At the moment I cannot figure out in which way. But it seems that it uses some noise (e. g. for "s") using a table with random values.

License

The software is a reverse-engineered version of a commercial software published more than 30 years ago. The current copyright holder is SoftVoice, Inc. (www.text2speech.com)

Any attempt to contact the company failed. The website was last updated in the year 2009. The status of the original software can therefore best described as Abandonware (http://en.wikipedia.org/wiki/Abandonware)

As long this is the case I cannot put my code under any specific open source software license Use it at your own risk.

Contact

If you have questions don' t hesitate to ask me. If you discovered some new knowledge about the code please mail me.

Sebastian Macke Email: sebastian@macke.de

About

Software Automatic Mouth - Tiny Speech Synthesizer

Resources

Stars

300 stars

Watchers

15 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Latest commit

History

145 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

SAM

Software Automatic Mouth - Tiny Speech Synthesizer

What is SAM?

Sam is a very small Text-To-Speech (TTS) program written in C, that runs on most popular platforms. It is an adaption to C of the speech software SAM (Software Automatic Mouth) for the Commodore C64 published in the year 1982 by Don't Ask Software (now SoftVoice, Inc.). It includes a Text-To-Phoneme converter called reciter and a Phoneme-To-Speech routine for the final output. It is so small that it will work also on embedded computers. On my computer it takes less than 39KB (much smaller on embedded devices as the executable-overhead is not necessary) of disk space and is a fully stand alone program. For immediate output it uses the SDL-library, otherwise it can save .wav files.

An online version and executables for Windows can be found on the web site: http://simulationcorner.net/index.php?page=sam

Compile

Simply type "make" in your command prompt. In order to compile without SDL remove the SDL statements from the CFLAGS and LFLAGS variables in the file "Makefile".

It should compile on every UNIX-like operating system. For Windows you need Cygwin or MinGW( + libsdl).

Usage

type

./sam I am Sam

for the first output.

If you have disabled SDL try

./sam -wav i_am_sam.wav I am Sam

to get a wav file. This file can be played by many media players available for the PC.

you can try other options like -pitch number -speed number -throat number -mouth number

Some typical values written in the original manual are:

DESCRIPTION SPEED PITCH THROAT MOUTH
Elf 72 64 110 160
Little Robot 92 60 190 190
Stuffy Guy 82 72 110 105
Little Old Lady 82 32 145 145
Extra-Terrestrial 100 64 150 200
SAM 72 64 128 128

It can even sing look at the file "sing" for a small example.

For the phoneme input table look in the Wiki.

A description of additional features can be found in the original manual at http://www.retrobits.net/atari/sam.shtml or in the manual of the equivalent Apple II program http://www.apple-iigs.info/newdoc/sam.pdf

Adaption To C

This program was converted semi-automatic into C by converting each assembler opcode. e. g.

lda 56 =>	A = mem[56];
jmp 38018 =>	goto pos38018;
inc 38 =>	mem[38]++;
. .
. .

Then it was manually rewritten to remove most of the jumps and register variables in the code and rename the variables to proper names. Most of the description below is a result of this rewriting process.

Unfortunately its still a not very good readable. But you should see where I started :)

Short description

First of all I will limit myself here to a very coarse description. There are very many exceptions defined in the source code that I will not explain. Also a lot of code is unknown for me e. g. Code47503. For a complete understanding of the code I need more time and especially more eyes have a look on the code.

Reciter

It changes the english text to phonemes by a ruleset shown in the wiki.

The rule " ANT(I)", "AY", means that if he find an "I" with previous letters " ANT", exchange the I by the phoneme "AY".

There are some special signs in this rules like # & @ ^ + : % which can mean e. g. that there must be a vocal or a consonant or something else.

With the -debug option you will get the corresponding rules and the resulting phonemes.

Output

Here is the full tree of subroutine calls:

SAMMain() Parser1() Parser2() Insert() CopyStress() SetPhonemeLength() Code48619() Code41240() Insert() Code48431() Insert()

Code48547
Code47574
Special1
Code47503
Code48227

SAMMain() is the entry routine and calls all further routines. Parser1 transforms the phoneme input and transforms it to three tables phonemeindex[] stress[] phonemelength[] (zero at this moment)

This tables are now changed:

Parser2 exchanges some phonemes by others and inserts new. CopyStress adds 1 to the stress under some circumstances SetPhonemeLength sets phoneme lengths. Code48619 changes the phoneme lengths Code41240 adds some additional phonemes Code48431 has some extra rules

The wiki shows all possible phonemes and some flag fields.
The final content of these tables can be seen with the -debug command.

In the function PrepareOutput() these tables are partly copied into the small tables: phonemeindexOutput[] stressOutput[] phonemelengthOutput[] for output.

Final Output

Except of some special phonemes the output is build by a linear combination:

A = A1 * sin ( f1 * t ) +
A2 * sin ( f2 * t ) +
A3 * rect( f3 * t )

where rect is a rectangular function with the same periodicity like sin. It seems really strange, but this is really enough for most types of phonemes.

Therefore the above phonemes are converted with some tables to pitches[] frequency1[] = f1 frequency2[] = f2 frequency3[] = f3 amplitude1[] = A1 amplitude2[] = A2 amplitude3[] = A3

Above formula is calculated in one very good omptimized routine. It only consist of 26 commands:

48087: LDX 43 ; get phase CLC LDA 42240,x	; load sine value (high 4 bits)
ORA TabAmpl1,y	; get amplitude (in low 4 bits)
TAX LDA 42752,x	; multiplication table
STA 56 ; store LDX 42 ; get phase
LDA 42240,x	; load sine value (high 4 bits)
ORA TabAmpl2,y	; get amplitude (in low 4 bits)
TAX LDA 42752,x	; multiplication table
ADC Var56	; add with previous values
STA 56 ; and store
LDX 41 ; get phase
LDA 42496,x	; load rect value (high 4 bits)
ORA TabAmpl3,y	; get amplitude (in low 4 bits)
TAX LDA 42752,x	; multiplication table
ADC 56 ; add with previous values
ADC #136 LSR A ; get highest 4 bits
LSR A LSR A LSR A STA 54296	;SID main output command

The rest is handled in a special way. At the moment I cannot figure out in which way. But it seems that it uses some noise (e. g. for "s") using a table with random values.

License

The software is a reverse-engineered version of a commercial software published more than 30 years ago. The current copyright holder is SoftVoice, Inc. (www.text2speech.com)

Any attempt to contact the company failed. The website was last updated in the year 2009. The status of the original software can therefore best described as Abandonware (http://en.wikipedia.org/wiki/Abandonware)

As long this is the case I cannot put my code under any specific open source software license Use it at your own risk.

Contact

If you have questions don' t hesitate to ask me. If you discovered some new knowledge about the code please mail me.

Sebastian Macke Email: sebastian@macke.de

About

Software Automatic Mouth - Tiny Speech Synthesizer

Resources

Stars

300 stars

Watchers

15 watching

Forks

Releases

Packages

Contributors

Languages