# SAMTTS

[![PyPI version][pypi_img]][pypi_link]
[![Downloads][downloads_img]][downloads_link]

  [pypi_img]: https://badge.fury.io/py/samtts.svg
  [pypi_link]: https://badge.fury.io/py/samtts
  [downloads_img]: https://pepy.tech/badge/samtts
  [downloads_link]: https://pepy.tech/project/samtts

[Documentation](https://jacklinquan.github.io/samtts)

A Python port of Software Automatic Mouth Test-To-Speech program.

- Ported by: Quan Lin
- License: None

***WARNING***:
This project is not under any open source software license.
Use it at your own risk.

---

## What is SAM?

SAM is the Text-To-Speech (TTS) software SAM (Software Automatic Mouth) for the Commodore C64
published in the year 1982 by Don't Ask Software (now SoftVoice, Inc.).

This project is an unofficial Python port of SAM. It is translated by hand from the adaption to C by
[Stefan Macke](https://github.com/s-macke/SAM)
and the refactorings by 
[Vidar Hokstad](https://github.com/vidarh/SAM).

---

## Installation

```shell
pip install samtts
```

---

## Usage

### Use `samtts` in Python script

The minimum example:

```python
from samtts import SamTTS

SamTTS().play("Hello. My name is Sam.")
```

A conversation between Sam and Little Robot:

```python
from samtts import SamTTS

# The default config is Sam.
sam = SamTTS()
# Config SamTTS for a different character.
robot = SamTTS(speed=92, pitch=60, mouth=190, throat=190)

sam.play("Hello. Little Robot. How are you today?")
robot.play("Hello! I am functioning well, thank you. How can I assist you today?")
sam.play("Could you hand me the hammer please?")
robot.play("Of course! Here you are.")
sam.play("Thank you very much!")
```

`SamTTS` does not pronouce all the words correctly.
Sometimes you may want to use phonemes directly.
Phonemes are powerful and flexible.
But make sure the phonemes are valid, otherwise it will raise exceptions.

```python
from samtts import SamTTS

# Make SamTTS say "Hello. My name is Sam." in phonemes.
SamTTS().play("/HEHLOH3OW. MAY4 NEY4M IHZ SAE4M.", phonetic=True)
```

Make `SamTTS` sing:

```python
from samtts import SamTTS

singer = SamTTS(speed=200, mouth=90, throat=90, sing_mode=True)
for pitch in (52, 41, 34, 41, 52):
    singer.play("AHAHAHAHAHAHAHAH", phonetic=True, pitch=pitch)
```

Save the audio data generated by `SamTTS` to a wav file:

```python
from samtts import SamTTS

SamTTS().save("Hello. My name is Sam.", "output.wav")
```

Use `SamTTS` with `asyncio`:

```python
import asyncio
from samtts import SamTTS

asyncio.run(SamTTS().async_play("Hello. My name is Sam."))
```

The core of `samtts` consists of `Reciter`, `Processor` and `Renderer`.
`SamTTS` is a combination of the three.
`Reciter` converts text to phonemes.
`Processor` and `Renderer` turns phonemes into audio data in `bytearray`.
But they can only process very short inputs.
To work around this,
`SamTTS` splits the input paragraph by punctuations `!,.:;?`.
It works for most of the cases, but not always.
You can design your own functions to split the input paragraph.

Make `SamTTS` read the paragraph word by word:

```python
from samtts import SamTTS

def iter_by_space(paragraph):
    for item in paragraph.split():
        yield item

SamTTS().play(
    "Hello. My name is Sam.",
    iter_segments_from_paragraph = iter_by_space,
)
```

In case you know your input is very small,
you do not have to split it at all:

```python
from samtts import SamTTS

def iter_no_split(paragraph):
    yield paragraph

SamTTS().play(
    "Hello. My name is Sam.",
    iter_segments_from_paragraph = iter_no_split,
)
```

By default `SamTTS` saves audio data in wav format.
But you can design your own save function
to save audio data in other formats:

```python
from samtts import SamTTS

# Make sure this function signature is followed.
def save_audio_data_in_other_formats(
    audio_data: bytes | bytearray,
    output_file_path: str,
    num_channels: int = 1,
    bytes_per_sample: int = 1,
    sample_rate: int = 22050,
):
    ...

SamTTS().save(
    "Hello. My name is Sam.",
    "output.ext",
    save_audio_data = save_audio_data_in_other_formats,
)
```

By default `SamTTS` plays audio with `simpleaudio` backend.
But you can design your own play audio function
to play audio with other audio backends:

```python
from samtts import SamTTS

# Make sure this function signature is followed.
def play_audio_data_with_other_backends(
    audio_data: bytes | bytearray,
    num_channels: int = 1,
    bytes_per_sample: int = 1,
    sample_rate: int = 22050,
):
    ...

SamTTS().play(
    "Hello. My name is Sam.",
    play_audio_data = play_audio_data_with_other_backends,
)
```

There are more examples in
[examples](https://github.com/jacklinquan/samtts/tree/master/examples)
directory.

### Use `samtts` with command line interface

To get help information:

```shell
python -m samtts
```

```text
 Usage: python -m samtts [OPTIONS] [INPUT_STRING]

 A python port of Software Automatic Mouth Test-To-Speech program.
 - If `--phoneme-info` or `--pitch-info` is used, the argument and all the other  
 options are ignored.
 - If `--phonetic` is used, the input must be valid phonemes.

╭─ Arguments ────────────────────────────────────────────────────────────────────╮
│   input_string      [INPUT_STRING]  Input text or phonemes.                    │
╰────────────────────────────────────────────────────────────────────────────────╯
╭─ Options ──────────────────────────────────────────────────────────────────────╮
│ --phoneme-info          --no-phoneme-info             Show phoneme info.       │
│                                                       [default:                │
│                                                       no-phoneme-info]         │
│ --pitch-info            --no-pitch-info               Show pitch info.         │
│                                                       [default: no-pitch-info] │
│ --phonetic              --no-phonetic                 Set phonetic flag.       │
│                                                       [default: no-phonetic]   │
│ --speed                                      INTEGER  Set speed value.         │
│                                                       [default: 72]            │
│ --pitch                                      INTEGER  Set pitch value.         │
│                                                       [default: 64]            │
│ --mouth                                      INTEGER  Set mouth value.         │
│                                                       [default: 128]           │
│ --throat                                     INTEGER  Set throat value.        │
│                                                       [default: 128]           │
│ --sing                  --no-sing                     Set sing mode.           │
│                                                       [default: no-sing]       │
│ --sample-rate                                INTEGER  Set sample rate 11025 or │
│                                                       22050.                   │
│                                                       [default: 22050]         │
│ --wav                                        TEXT     Set output wav file name │
│                                                       or path.                 │
│ --debug                 --no-debug                    Set debug flag.          │
│                                                       [default: no-debug]      │
│ --install-completion                                  Install completion for   │
│                                                       the current shell.       │
│ --show-completion                                     Show completion for the  │
│                                                       current shell, to copy   │
│                                                       it or customize the      │
│                                                       installation.            │
│ --help                                                Show this message and    │
│                                                       exit.                    │
╰────────────────────────────────────────────────────────────────────────────────╯
```

The minimum example:

```shell
python -m samtts "Hello. My name is Sam."
```

To config its voice:

```shell
python -m samtts --speed 92 --pitch 60 --mouth 190 --throat 190 "Hello. My name is Little Robot."
```

To save to a wav file:

```shell
python -m samtts --wav "output.wav" "Hello. My name is Sam."
```

---

## Useful information

### Phonemes

```text
                 Phoneme Information

     VOWELS                             VOICED CONSONANTS
IY           f(ee)t                     R        red
IH           p(i)n                      L        allow
EH           beg                        W        away
AE           Sam                        W        whale
AA           pot                        Y        you
AH           b(u)dget                   M        Sam
AO           t(al)k                     N        man
OH           cone                       NX       so(ng)
UH           book                       B        bad
UX           l(oo)t                     D        dog
ER           bird                       G        again
AX           gall(o)n                   J        judge
IX           dig(i)t                    Z        zoo
                                        ZH       plea(s)ure
   DIPHTHONGS                           V        seven
EY           m(a)de                     DH       (th)en
AY           h(igh)
OY           boy
AW           h(ow)                      UNVOICED CONSONANTS
OW           slow                       S         Sam
UW           crew                       Sh        fish
                                        F         fish
                                        TH        thin
 SPECIAL PHONEMES                       P         poke
UL           sett(le) (=AXL)            T         talk
UM           astron(omy) (=AXM)         K         cake
UN           functi(on) (=AXN)          CH        speech
Q            kitt-en (glottal stop)     /H        a(h)ead
```

### Pitches

```text
                  Pitch Information

PITCH   NOTE    |   PITCH   NOTE    |   PITCH   NOTE
 104     C1     |     52     C2     |     26     C3
  92     D1     |     46     D2     |     23     D3
  82     E1     |     41     E2     |     21     E3
  78     F1     |     39     F2     |     19     F3
  68     G1     |     34     G2     |     17     G3
  62     A1     |     31     A2     |
  55     B1     |     28     B2     |
```

### Characters

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

---

## Limitations

- SAM was developed more than 40 years ago.
  It was advanced in 1980s.
  But now its sound quality is not comparable to AI based TTS programs.
- The core of SAM can only process very short inputs.
  To work around this, long inputs must be split.
- SAM does not pronouce all the words correctly.
  To work around this, phonemes can be used directly.
  But make sure the phonemes are valid, otherwise it will raise exceptions.

---

## Further development

This project is meant to be a fairly faithful port of the original SAM.
It will not improve upon SAM in any manner,
like improving the quality of the sound or
breaking the limitations of SAM.

The further development of this project is limited to bug fixing.
If anyone is interested in improving it,
please fork it and start a new project.

---

## About license

According to
[Stefan Macke](https://github.com/jacklinquan/samtts/blob/master/Stefan_Macke_SAM_README.md)
and
[Vidar Hokstad](https://github.com/jacklinquan/samtts/blob/master/Vidar_Hokstad_SAM_README.md)
the status of the original software can be best described as
[Abandonware](https://en.wikipedia.org/wiki/Abandonware).

Neither Stefan Macke nor Vidar Hokstad put their projects under any open source software license.
As long this is the case I cannot put my code under any open source software license either.
However the software might be used under the
["Fair Use" act](https://en.wikipedia.org/wiki/FAIR_USE_Act)
in the USA.

---

## References

[Software Automatic Mouth on wikipedia](https://en.wikipedia.org/wiki/Software_Automatic_Mouth)

[SAM in C by Stefan Macke](https://github.com/s-macke/SAM)

[Refactored SAM in C by Vidar Hokstad](https://github.com/vidarh/SAM)

[SAM in Javascript by Christian Schiffler](https://github.com/discordier/sam)
