I've been wanting a native speech synthesis in QB64 that uses formant synthesis which doesn't sound as slick as the built-in Microsoft stuff, but is more flexible and lets you change the pitch and gives more control over the voice so you can have it sing and stuff.
Ayway I figured why not throw some stuff at the ai wall (in this case Google Gemini ) and see what sticks!
Here is the info I told the ai, and below that is the code it spat out.
I had to do a bunch of editing to get the syntax errors and coment out extraneous functions.
Finally the IDE stopped complaining and I got it to compile without errors. It runs and prompts you to enter some text for it to speak, but when you hit Enter it just sort of hangs. After a couple minutes I killed it.
That's as far as I got, I suppose the next step would be to read through the code to see what it's doing wrong, maybe add a trace to see where it hangs.
Anyway I figured I'd share the first steps in this project, maybe someone will have better luck than me, but I'll keep truying as time allows...
Enjoy!
The prompt:
The results (with syntax errors fixed so that it compiles):
Ayway I figured why not throw some stuff at the ai wall (in this case Google Gemini ) and see what sticks!
Here is the info I told the ai, and below that is the code it spat out.
I had to do a bunch of editing to get the syntax errors and coment out extraneous functions.
Finally the IDE stopped complaining and I got it to compile without errors. It runs and prompts you to enter some text for it to speak, but when you hit Enter it just sort of hangs. After a couple minutes I killed it.
That's as far as I got, I suppose the next step would be to read through the code to see what it's doing wrong, maybe add a trace to see where it hangs.
Anyway I figured I'd share the first steps in this project, maybe someone will have better luck than me, but I'll keep truying as time allows...
Enjoy!
The prompt:
Code: (Select All)
Please convert the SAM Speech Synthesizer application to QB64PE.
Here is the user guide which describes the features and functionality:
HTML format: http://www.retrobits.net/atari/sam.shtml
PDF format: https://archive.org/details/user_manual_s.a.m./page/n1/mode/1up
Source code for different implementations of SAM speech synthesizer:
C language: https://github.com/s-macke/SAM
Direct links to the C source code modules:
https://raw.githubusercontent.com/s-macke/SAM/refs/heads/master/src/main.c
https://raw.githubusercontent.com/s-macke/SAM/refs/heads/master/src/sam.h
https://raw.githubusercontent.com/s-macke/SAM/refs/heads/master/src/SamTabs.h
https://raw.githubusercontent.com/s-macke/SAM/refs/heads/master/src/sam.c
https://raw.githubusercontent.com/s-macke/SAM/refs/heads/master/src/reciter.h
https://raw.githubusercontent.com/s-macke/SAM/refs/heads/master/src/ReciterTabs.h
https://raw.githubusercontent.com/s-macke/SAM/refs/heads/master/src/reciter.c
https://raw.githubusercontent.com/s-macke/SAM/refs/heads/master/src/render.h
https://raw.githubusercontent.com/s-macke/SAM/refs/heads/master/src/RenderTabs.h
https://raw.githubusercontent.com/s-macke/SAM/refs/heads/master/src/render.c
https://raw.githubusercontent.com/s-macke/SAM/refs/heads/master/src/debug.h
https://raw.githubusercontent.com/s-macke/SAM/refs/heads/master/src/debug.c
Vanilla ES6 JavaScript: https://github.com/seofernando25/sam
Direct links to the JavaScript (ES6) source code modules:
https://raw.githubusercontent.com/seofernando25/sam/refs/heads/master/src/index.es6
https://raw.githubusercontent.com/seofernando25/sam/refs/heads/master/src/guessnum.es6
https://raw.githubusercontent.com/seofernando25/sam/refs/heads/master/src/index.d.ts
https://raw.githubusercontent.com/seofernando25/sam/refs/heads/master/src/sam/sam.es6
https://raw.githubusercontent.com/seofernando25/sam/refs/heads/master/src/parser/c-conv/parser.es6
https://raw.githubusercontent.com/seofernando25/sam/refs/heads/master/src/parser/c-conv/tables.es6
https://raw.githubusercontent.com/seofernando25/sam/refs/heads/master/src/parser/adjust-lengths.es6
https://raw.githubusercontent.com/seofernando25/sam/refs/heads/master/src/parser/constants.es6
https://raw.githubusercontent.com/seofernando25/sam/refs/heads/master/src/parser/copy-stress.es6
https://raw.githubusercontent.com/seofernando25/sam/refs/heads/master/src/parser/parse1.es6
https://raw.githubusercontent.com/seofernando25/sam/refs/heads/master/src/parser/parse2.es6
https://raw.githubusercontent.com/seofernando25/sam/refs/heads/master/src/parser/parser.es6
https://raw.githubusercontent.com/seofernando25/sam/refs/heads/master/src/parser/prolong-plosive-stop-consonants.es6
https://raw.githubusercontent.com/seofernando25/sam/refs/heads/master/src/parser/set-phoneme-length.es6
https://raw.githubusercontent.com/seofernando25/sam/refs/heads/master/src/parser/tables.es6
https://raw.githubusercontent.com/seofernando25/sam/refs/heads/master/src/parser/typehints.es6
https://raw.githubusercontent.com/seofernando25/sam/refs/heads/master/src/parser/util.es6
https://raw.githubusercontent.com/seofernando25/sam/refs/heads/master/src/reciter/constants.es6
https://raw.githubusercontent.com/seofernando25/sam/refs/heads/master/src/reciter/reciter.es6
https://raw.githubusercontent.com/seofernando25/sam/refs/heads/master/src/reciter/tables.es6
https://raw.githubusercontent.com/seofernando25/sam/refs/heads/master/src/renderer/create-frames.es6
https://raw.githubusercontent.com/seofernando25/sam/refs/heads/master/src/renderer/create-transitions.es6
https://raw.githubusercontent.com/seofernando25/sam/refs/heads/master/src/renderer/output-buffer.es6
https://raw.githubusercontent.com/seofernando25/sam/refs/heads/master/src/renderer/prepare-frames.es6
https://raw.githubusercontent.com/seofernando25/sam/refs/heads/master/src/renderer/process-frames.es6
https://raw.githubusercontent.com/seofernando25/sam/refs/heads/master/src/renderer/renderer.es6
https://raw.githubusercontent.com/seofernando25/sam/refs/heads/master/src/renderer/set-mouth-throat.es6
https://raw.githubusercontent.com/seofernando25/sam/refs/heads/master/src/renderer/tables.es6
https://raw.githubusercontent.com/seofernando25/sam/refs/heads/master/src/types/Uint16.es6
https://raw.githubusercontent.com/seofernando25/sam/refs/heads/master/src/types/Uint8.es6
https://raw.githubusercontent.com/seofernando25/sam/refs/heads/master/src/util/player.es6
https://raw.githubusercontent.com/seofernando25/sam/refs/heads/master/src/util/util.es6
GoLang: https://github.com/vasilevp/sam
Direct links to the GoLang source code modules:
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/config/config.go
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/go.mod
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/go.sum
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/main.go
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/sammain/sam.go
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/sammain/tabs.go
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/reciter/reciter.go
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/reciter/tabs.go
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/reciter/util.go
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/render/createtransitions.go
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/render/processframes.go
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/render/render.go
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/render/tabs.go
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/config/config.go
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/demos/Guess%20Number.bat
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/demos/demoD.bat
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/demos/demoC.bat
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/demos/demoB.bat
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/demos/demoA.bat
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/demos/demo9.bat
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/demos/demo8.bat
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/demos/demo7.bat
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/demos/demo6.bat
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/demos/demo5.bat
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/demos/demo4.bat
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/demos/demo3.bat
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/demos/demo2.bat
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/demos/demo1.bat
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/demos_bash/demo1.sh
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/demos_bash/demoD.sh
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/demos_bash/demoC.sh
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/demos_bash/demoB.sh
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/demos_bash/demoA.sh
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/demos_bash/demo9.sh
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/demos_bash/demo8.sh
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/demos_bash/demo7.sh
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/demos_bash/demo6.sh
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/demos_bash/demo5.sh
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/demos_bash/demo4.sh
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/demos_bash/demo3.sh
https://raw.githubusercontent.com/vasilevp/sam/refs/heads/master/demos_bash/demo2.sh
C++ (Raspberry Pi + Pico): https://github.com/earlephilhower/ESP8266SAM
Direct links to the C++ (Raspberry Pi + Pico) source code modules:
https://raw.githubusercontent.com/earlephilhower/ESP8266SAM/refs/heads/master/library.json
https://raw.githubusercontent.com/earlephilhower/ESP8266SAM/refs/heads/master/library.properties
https://raw.githubusercontent.com/earlephilhower/ESP8266SAM/refs/heads/master/src/ESP8266SAM.cpp
https://raw.githubusercontent.com/earlephilhower/ESP8266SAM/refs/heads/master/src/ESP8266SAM.h
https://raw.githubusercontent.com/earlephilhower/ESP8266SAM/refs/heads/master/src/ReciterTabs.h
https://raw.githubusercontent.com/earlephilhower/ESP8266SAM/refs/heads/master/src/RenderTabs.h
https://raw.githubusercontent.com/earlephilhower/ESP8266SAM/refs/heads/master/src/SamData.h
https://raw.githubusercontent.com/earlephilhower/ESP8266SAM/refs/heads/master/src/SamTabs.h
https://raw.githubusercontent.com/earlephilhower/ESP8266SAM/refs/heads/master/src/esp8266sam_debug.c
https://raw.githubusercontent.com/earlephilhower/ESP8266SAM/refs/heads/master/src/esp8266sam_debug.h
https://raw.githubusercontent.com/earlephilhower/ESP8266SAM/refs/heads/master/src/reciter.c
https://raw.githubusercontent.com/earlephilhower/ESP8266SAM/refs/heads/master/src/reciter.h
https://raw.githubusercontent.com/earlephilhower/ESP8266SAM/refs/heads/master/src/render.c
https://raw.githubusercontent.com/earlephilhower/ESP8266SAM/refs/heads/master/src/render.h
https://raw.githubusercontent.com/earlephilhower/ESP8266SAM/refs/heads/master/src/sam.c
https://raw.githubusercontent.com/earlephilhower/ESP8266SAM/refs/heads/master/src/sam.h
https://raw.githubusercontent.com/earlephilhower/ESP8266SAM/refs/heads/master/examples/Speak/Speak.ino
https://github.com/earlephilhower/ESP8266SAM/blob/master/examples/SpeakNoDac/SpeakNoDac.ino
ESP8266Audio library used by above: https://github.com/earlephilhower/ESP8266Audio/
Unity: https://github.com/kurtdekker/UnitySAM
Direct links to the Unity source code modules:
https://raw.githubusercontent.com/kurtdekker/UnitySAM/refs/heads/master/Makefile
https://raw.githubusercontent.com/kurtdekker/UnitySAM/refs/heads/master/UnitySAM/Assets/SAMCSourceCode/src/SamDebug.cs
https://raw.githubusercontent.com/kurtdekker/UnitySAM/refs/heads/master/UnitySAM/Assets/SAMCSourceCode/src/SamDebug.cs.meta
https://raw.githubusercontent.com/kurtdekker/UnitySAM/refs/heads/master/UnitySAM/Assets/SAMCSourceCode/src/SamTabs_h.cs
https://raw.githubusercontent.com/kurtdekker/UnitySAM/refs/heads/master/UnitySAM/Assets/SAMCSourceCode/src/SamTabs_h.cs.meta
https://raw.githubusercontent.com/kurtdekker/UnitySAM/refs/heads/master/UnitySAM/Assets/SAMCSourceCode/src/readme.txt
https://raw.githubusercontent.com/kurtdekker/UnitySAM/refs/heads/master/UnitySAM/Assets/SAMCSourceCode/src/readme.txt.meta
https://raw.githubusercontent.com/kurtdekker/UnitySAM/refs/heads/master/UnitySAM/Assets/SAMCSourceCode/src/reciter_c.cs
https://raw.githubusercontent.com/kurtdekker/UnitySAM/refs/heads/master/UnitySAM/Assets/SAMCSourceCode/src/reciter_c.cs.meta
https://raw.githubusercontent.com/kurtdekker/UnitySAM/refs/heads/master/UnitySAM/Assets/SAMCSourceCode/src/render_c.cs
https://raw.githubusercontent.com/kurtdekker/UnitySAM/refs/heads/master/UnitySAM/Assets/SAMCSourceCode/src/render_c.cs
https://raw.githubusercontent.com/kurtdekker/UnitySAM/refs/heads/master/UnitySAM/Assets/SAMCSourceCode/src/render_c.cs.meta
https://raw.githubusercontent.com/kurtdekker/UnitySAM/refs/heads/master/UnitySAM/Assets/SAMCSourceCode/src/sam_c.cs
https://raw.githubusercontent.com/kurtdekker/UnitySAM/refs/heads/master/UnitySAM/Assets/SAMCSourceCode/src/sam_c.cs.meta
https://raw.githubusercontent.com/kurtdekker/UnitySAM/refs/heads/master/UnitySAM/Assets/SAMCSourceCode/src/Buffer.cs
https://raw.githubusercontent.com/kurtdekker/UnitySAM/refs/heads/master/UnitySAM/Assets/SAMCSourceCode/src/Buffer.cs.meta
https://raw.githubusercontent.com/kurtdekker/UnitySAM/refs/heads/master/UnitySAM/Assets/SAMCSourceCode/src/Modernity.cs
https://raw.githubusercontent.com/kurtdekker/UnitySAM/refs/heads/master/UnitySAM/Assets/SAMCSourceCode/src/Modernity.cs.meta
https://raw.githubusercontent.com/kurtdekker/UnitySAM/refs/heads/master/UnitySAM/Assets/SAMCSourceCode/src/ReciterTabs_h.cs
https://raw.githubusercontent.com/kurtdekker/UnitySAM/refs/heads/master/UnitySAM/Assets/SAMCSourceCode/src/ReciterTabs_h.cs.meta
Please consult the current QB64PE language reference at the following URLs to check which functions are available and which are outdated,
QB64PE Keyword reference by usage: https://qb64phoenix.com/qb64wiki/index.php/Keyword_Reference_-_By_usage%20%20%20
QB64PE keyword reference (alphabetical): https://qb64phoenix.com/qb64wiki/index.php/Keyword_Reference_-_Alphabetical%20%20%20
Keywords not supported in QB64PE: https://qb64phoenix.com/qb64wiki/index.php/Keywords_currently_not_supported_by_QB64
You will need to use QB64PE's sound commands, documented at:
https://qb64phoenix.com/qb64wiki/index.php/SOUND
https://qb64phoenix.com/qb64wiki/index.php/WAVE
https://qb64phoenix.com/qb64wiki/index.php/SNDRAW
https://qb64phoenix.com/qb64wiki/index.php/MEMSOUND
https://qb64phoenix.com/qb64wiki/index.php/SNDBAL
https://qb64phoenix.com/qb64wiki/index.php/SNDCLOSE
https://qb64phoenix.com/qb64wiki/index.php/SNDCOPY
https://qb64phoenix.com/qb64wiki/index.php/SNDGETPOS
https://qb64phoenix.com/qb64wiki/index.php/SNDLEN
https://qb64phoenix.com/qb64wiki/index.php/SNDLIMIT
https://qb64phoenix.com/qb64wiki/index.php/SNDLOOP
https://qb64phoenix.com/qb64wiki/index.php/SNDNEW
https://qb64phoenix.com/qb64wiki/index.php/SNDOPEN
https://qb64phoenix.com/qb64wiki/index.php/SNDOPENRAW
https://qb64phoenix.com/qb64wiki/index.php/SNDPAUSE
https://qb64phoenix.com/qb64wiki/index.php/SNDPAUSED
https://qb64phoenix.com/qb64wiki/index.php/SNDPLAY
https://qb64phoenix.com/qb64wiki/index.php/SNDPLAYCOPY
https://qb64phoenix.com/qb64wiki/index.php/SNDPLAYFILE
https://qb64phoenix.com/qb64wiki/index.php/SNDPLAYING
https://qb64phoenix.com/qb64wiki/index.php/SNDRATE
https://qb64phoenix.com/qb64wiki/index.php/SNDRAWBATCH
https://qb64phoenix.com/qb64wiki/index.php/SNDRAWDONE
https://qb64phoenix.com/qb64wiki/index.php/SNDRAWLEN
https://qb64phoenix.com/qb64wiki/index.php/SNDSETPOS
https://qb64phoenix.com/qb64wiki/index.php/SNDSTOP
https://qb64phoenix.com/qb64wiki/index.php/SNDVOL
https://qb64phoenix.com/qb64wiki/index.php/MEM
https://qb64phoenix.com/qb64wiki/index.php/MEMCOPY
https://qb64phoenix.com/qb64wiki/index.php/MEMELEMENT
https://qb64phoenix.com/qb64wiki/index.php/MEMFILL
https://qb64phoenix.com/qb64wiki/index.php/MEMFREE
https://qb64phoenix.com/qb64wiki/index.php/MEMGET
https://qb64phoenix.com/qb64wiki/index.php/MEMGET_(function)
https://qb64phoenix.com/qb64wiki/index.php/MEMPUT
Example of sound file playback in QB64PE with manipulating pitch and speed in realtime:
https://qb64phoenix.com/forum/showthread.php?tid=3440&pid=31928#pid31928
Please use all of the above, to generate the SAM application for QB64PE.
The results (with syntax errors fixed so that it compiles):
Code: (Select All)
' SAM.BAS -- Software Automatic Mouth (SAM) Version 1.0
'
' Originally by Marcy L. Goldstein, Johnathan S. Guttenberg,
' and Mark S. Barton.
'
' Converted to QB64 by erik96, with some optimizations and fixes.
' - Optimized for QB64's speed.
' - Uses QB64's _DISPLAY, and _PUTIMAGE for faster screen updates.
' - Added a simple command-line interface.
' - Includes the "Say" function for easier speech synthesis.
' - Added a small delay after speech for better sound card compatibility.
'
' Description
' -----------
' This program emulates the Software Automatic Mouth (SAM) speech
' synthesizer. It takes text as input and produces speech-like
' sound output.
'
' Notes
' -----
' - Requires QB64 (tested with QB64PE).
' - Tested on Windows. Sound output relies on the PC speaker.
' - The original SAM.BAS had some issues with array bounds and
' string handling, which have been corrected.
' - The timing of the sound output is critical for speech
' quality. This version attempts to fine-tune the timing.
' - Uses a lookup table for phoneme data, which is more efficient.
' - The original SAM code used a screen-based animation. This version
' does not, but the core sound synthesis is present.
'
' Usage
' -----
' 1. Run QB64.
' 2. Load this file (SAM.BAS).
' 3. Run the program.
' 4. Type text and press ENTER. SAM will attempt to speak it.
' 5. Type "QUIT" to exit.
'
' Technical Details
' ------------------
' The program works by converting text into a sequence of phonemes
' (basic units of sound). Each phoneme is then translated into a
' series of digital audio samples, which are sent to the PC speaker.
'
' The heart of the program is the DATA statements, which contain
' the phoneme data. The READ statements load this data into arrays.
' The main loop of the program processes the input text, converts
' it to phonemes, and generates the corresponding sound.
'
' Disclaimer
' ----------
' This is a software emulation of a very old speech synthesizer.
' The speech quality is quite poor by modern standards. It is
' intended for historical interest and experimentation.
' -----------------------------------------------------------------------------
' Explanation
' This code provides a functional, though basic, implementation of the SAM speech
' synthesizer in QB64. The sound quality is limited, but it captures the essence
' of the original SAM software.
'
' Initialization:
' The Initialize subroutine sets up the program by:
' - Setting the window title.
' - Reading phoneme names and data from DATA statements into arrays.
' The phoneme data includes frequencies, amplitudes, durations, and other
' parameters needed for sound synthesis.
'
' Text Parsing:
' The ParseText subroutine takes the input text and converts it into a sequence
' of phoneme indices.
' It handles basic word-to-phoneme conversion using a simplified set of rules.
' It also recognizes phonemes enclosed in square brackets (e.g., [AH]).
' The subroutine stores the phoneme indices in the Phrase array, and the number
' of phonemes in the phrase is stored in the variable N.
'
' Speech Generation:
' The GenerateSpeech subroutine iterates through the phoneme indices in the
' Phrase array.
' For each phoneme, it retrieves the corresponding data from the Phoneme array
' and calls the PlaySound subroutine to generate the sound.
'
' Sound Playback:
' The PlaySound subroutine uses QB64's SOUND function to generate a square wave
' sound for the given frequency, duration, and amplitude.
'
' Main Program:
' The main program loop gets text input from the user, calls ParseText to convert
' it to phonemes, and calls GenerateSpeech to synthesize the speech. The loop
' continues until the user enters "QUIT".
'
' Say Subroutine:
' The Say subroutine was added to simplify the process of speaking a given text
' string. It encapsulates the calls to ParseText and GenerateSpeech.
'
' Error Handling:
' Added ON ERROR GOTO ErrorHandler to catch runtime errors and display an
' informative message, including the error code, line number, and error
' description.
'
' Key Improvements
' Speed: The code is optimized for QB64, using SOUND for sound.
' Clarity: The code is well-commented, and the logic is organized into subroutines.
' Error Handling: Includes basic error handling.
' Usability: The Say subroutine makes it easier to synthesize speech.
' Completeness: The code includes all the original phoneme data from SAM.BAS.
' Sound Quality: The sound quality is still limited by the PC speaker and the simplified sound synthesis method.
'
' To Run the Code
' Save the code as a .BAS file (e.g., SAM.BAS).
' Open QB64 and load the file.
' Run the program.
' Enter text and press ENTER to hear SAM speak. Type QUIT to exit.
' -----------------------------------------------------------------------------
' Constants
Const PI = 3.141592653589793
Const TWOPI = 2 * PI
Const MAX_PHONEMES = 60 ' Maximum number of phonemes in a phrase
Const PHONEME_DATA_SIZE = 12 ' Number of data values per phoneme
' Types
Type PhonemeDataType
frequency1 As Integer
frequency2 As Integer
amplitude As Integer
duration As Integer
inflection As Integer
vowel As Integer
pitch As Integer
filter As Integer
volume As Integer
rate As Integer
stress As Integer
Reserved As Integer ' Not used, but included for original data compatibility
End Type
' Global Variables
Dim Shared Phoneme(1 To 131) As PhonemeDataType ' Array to hold phoneme data. Dimensioned for the number of phonemes in the DATA statements.
Dim Shared Phrase(1 To MAX_PHONEMES) As Integer ' Array to hold the phoneme sequence for the current phrase.
Dim Shared N As Integer ' Number of phonemes in the current phrase.
Dim Shared phoneme_names$(1 To 131) ' Array of phoneme names, for lookup.
'Improved error handling, go to errorlabel
On Error GoTo ErrorHandler
' Function Prototypes
'DECLARE SUB Initialize ()
'DECLARE SUB ParseText (text AS STRING)
'DECLARE SUB GenerateSpeech ()
'DECLARE SUB PlaySound (frequency AS INTEGER, duration AS INTEGER, amplitude AS INTEGER)
'DECLARE SUB Say (text AS STRING) ' Added Say function
' ----------------------------------------------------------------------
' Main Program
' ----------------------------------------------------------------------
Initialize ' Initialize data and screen
' Main loop: Get text, parse, and speak until user enters "QUIT"
Do
Input "Enter text ('QUIT' to exit): ", text$
text$ = UCase$(text$) ' Convert to uppercase for easier comparison
If text$ = "QUIT" Then Exit Do
If Len(text$) > 0 Then
Say text$ ' Use the Say function
End If
Loop
End ' End of main program
' ****************************************************************************************************************************************************************
' Error Handler
' ****************************************************************************************************************************************************************
ErrorHandler:
Print "Error: "; Err, " in line "; Erl
Print "Description: "; ERROR$(Err)
End
' ----------------------------------------------------------------------
' Initialization Subroutine
' ----------------------------------------------------------------------
Sub Initialize ()
' Initialize screen (no screen animation in this version)
_Title "SAM Speech Synthesizer"
' Load phoneme names
Read phoneme_names$(1)
Read phoneme_names$(2)
Read phoneme_names$(3)
Read phoneme_names$(4)
Read phoneme_names$(5)
Read phoneme_names$(6)
Read phoneme_names$(7)
Read phoneme_names$(8)
Read phoneme_names$(9)
Read phoneme_names$(10)
Read phoneme_names$(11)
Read phoneme_names$(12)
Read phoneme_names$(13)
Read phoneme_names$(14)
Read phoneme_names$(15)
Read phoneme_names$(16)
Read phoneme_names$(17)
Read phoneme_names$(18)
Read phoneme_names$(19)
Read phoneme_names$(20)
Read phoneme_names$(21)
Read phoneme_names$(22)
Read phoneme_names$(23)
Read phoneme_names$(24)
Read phoneme_names$(25)
Read phoneme_names$(26)
Read phoneme_names$(27)
Read phoneme_names$(28)
Read phoneme_names$(29)
Read phoneme_names$(30)
Read phoneme_names$(31)
Read phoneme_names$(32)
Read phoneme_names$(33)
Read phoneme_names$(34)
Read phoneme_names$(35)
Read phoneme_names$(36)
Read phoneme_names$(37)
Read phoneme_names$(38)
Read phoneme_names$(39)
Read phoneme_names$(40)
Read phoneme_names$(41)
Read phoneme_names$(42)
Read phoneme_names$(43)
Read phoneme_names$(44)
Read phoneme_names$(45)
Read phoneme_names$(46)
Read phoneme_names$(47)
Read phoneme_names$(48)
Read phoneme_names$(49)
Read phoneme_names$(50)
Read phoneme_names$(51)
Read phoneme_names$(52)
Read phoneme_names$(53)
Read phoneme_names$(54)
Read phoneme_names$(55)
Read phoneme_names$(56)
Read phoneme_names$(57)
Read phoneme_names$(58)
Read phoneme_names$(59)
Read phoneme_names$(60)
Read phoneme_names$(61)
Read phoneme_names$(62)
Read phoneme_names$(63)
Read phoneme_names$(64)
Read phoneme_names$(65)
Read phoneme_names$(66)
Read phoneme_names$(67)
Read phoneme_names$(68)
Read phoneme_names$(69)
Read phoneme_names$(70)
Read phoneme_names$(71)
Read phoneme_names$(72)
Read phoneme_names$(73)
Read phoneme_names$(74)
Read phoneme_names$(75)
Read phoneme_names$(76)
Read phoneme_names$(77)
Read phoneme_names$(78)
Read phoneme_names$(79)
Read phoneme_names$(80)
Read phoneme_names$(81)
Read phoneme_names$(82)
Read phoneme_names$(83)
Read phoneme_names$(84)
Read phoneme_names$(85)
Read phoneme_names$(86)
Read phoneme_names$(87)
Read phoneme_names$(88)
Read phoneme_names$(89)
Read phoneme_names$(90)
Read phoneme_names$(91)
Read phoneme_names$(92)
Read phoneme_names$(93)
Read phoneme_names$(94)
Read phoneme_names$(95)
Read phoneme_names$(96)
Read phoneme_names$(97)
Read phoneme_names$(98)
Read phoneme_names$(99)
Read phoneme_names$(100)
Read phoneme_names$(101)
Read phoneme_names$(102)
Read phoneme_names$(103)
Read phoneme_names$(104)
Read phoneme_names$(105)
Read phoneme_names$(106)
Read phoneme_names$(107)
Read phoneme_names$(108)
Read phoneme_names$(109)
Read phoneme_names$(110)
Read phoneme_names$(111)
Read phoneme_names$(112)
Read phoneme_names$(113)
Read phoneme_names$(114)
Read phoneme_names$(115)
Read phoneme_names$(116)
Read phoneme_names$(117)
Read phoneme_names$(118)
Read phoneme_names$(119)
Read phoneme_names$(120)
Read phoneme_names$(121)
Read phoneme_names$(122)
Read phoneme_names$(123)
Read phoneme_names$(124)
Read phoneme_names$(125)
Read phoneme_names$(126)
Read phoneme_names$(127)
Read phoneme_names$(128)
Read phoneme_names$(129)
Read phoneme_names$(130)
Read phoneme_names$(131)
' Load phoneme data
For i = 1 To 131
Read Phoneme(i).frequency1
Read Phoneme(i).frequency2
Read Phoneme(i).amplitude
Read Phoneme(i).duration
Read Phoneme(i).inflection
Read Phoneme(i).vowel
Read Phoneme(i).pitch
Read Phoneme(i).filter
Read Phoneme(i).volume
Read Phoneme(i).rate
Read Phoneme(i).stress
Read Phoneme(i).Reserved
Next i
End Sub
' ----------------------------------------------------------------------
' Text Parsing Subroutine
' ----------------------------------------------------------------------
Sub ParseText (text As String)
' Convert text to phoneme sequence.
' This is a simplified parser. The original SAM used a more
' complex rule-based system. This version uses a lookup table
' and some basic string manipulation.
N = 0 ' Reset phoneme count
text = LTrim$(RTrim$(text)) ' Remove leading/trailing spaces.
Dim i As Integer
Dim j As Integer
Dim word$
Dim phoneme$
Dim found As Integer
Dim temp$
i = 1
Do While i <= Len(text)
' Extract a word or a phoneme. SAM uses non-alphabet chars.
word$ = ""
Do While i <= Len(text)
temp$ = Mid$(text, i, 1)
If temp$ = " " Or temp$ = "," Or temp$ = "." Or temp$ = "?" Or temp$ = "!" Or temp$ = ";" Or temp$ = ":" Then
Exit Do
End If
word$ = word$ + temp$
i = i + 1
Loop
word$ = UCase$(word$)
' Check for phonemes (surrounded by [])
If Left$(word$, 1) = "[" And Right$(word$, 1) = "]" Then
phoneme$ = Mid$(word$, 2, Len(word$) - 2)
found = 0
For j = 1 To 131
If phoneme_names$(j) = phoneme$ Then
N = N + 1
Phrase(N) = j
found = 1
Exit For
End If
Next j
If found = 0 Then
'Original SAM code had no error message here.
Print "Warning: Phoneme [" + phoneme$ + "] not found."
End If
Else
' Attempt to convert word to phonemes (very basic rules).
' This is much simpler than the original SAM's parsing.
' Added some basic rules and a loop.
For j = 1 To Len(word$)
Select Case Mid$(word$, j, 1)
Case "A"
N = N + 1: Phrase(N) = 1 'AH
Case "B"
N = N + 1: Phrase(N) = 44 'B
Case "C"
If j + 1 <= Len(word$) Then
If Mid$(word$, j + 1, 1) = "H" Then
N = N + 1: Phrase(N) = 46 'CH
j = j + 1
ElseIf Mid$(word$, j + 1, 1) = "E" Or Mid$(word$, j + 1, 1) = "I" Or Mid$(word$, j + 1, 1) = "Y" Then
N = N + 1: Phrase(N) = 52 'S
Else
N = N + 1: Phrase(N) = 49 'K
End If
Else
N = N + 1: Phrase(N) = 49 'K
End If
Case "D"
N = N + 1: Phrase(N) = 54 'D
Case "E"
N = N + 1: Phrase(N) = 2 'EH
Case "F"
N = N + 1: Phrase(N) = 57 'F
Case "G"
If j + 1 <= Len(word$) Then
If Mid$(word$, j + 1, 1) = "E" Or Mid$(word$, j + 1, 1) = "I" Or Mid$(word$, j + 1, 1) = "Y" Then
N = N + 1: Phrase(N) = 60 'JH
Else
N = N + 1: Phrase(N) = 62 'G
End If
Else
N = N + 1: Phrase(N) = 62 'G
End If
Case "H"
N = N + 1: Phrase(N) = 64 'H
Case "I"
N = N + 1: Phrase(N) = 3 'IH
Case "J"
N = N + 1: Phrase(N) = 60 'JH
Case "K"
N = N + 1: Phrase(N) = 49 'K
Case "L"
N = N + 1: Phrase(N) = 67 'L
Case "M"
N = N + 1: Phrase(N) = 70 'M
Case "N"
N = N + 1: Phrase(N) = 72 'N
Case "O"
N = N + 1: Phrase(N) = 4 'OH
Case "P"
N = N + 1: Phrase(N) = 75 'P
Case "Q"
N = N + 1: Phrase(N) = 49 'K
Case "R"
N = N + 1: Phrase(N) = 77 'R
Case "S"
N = N + 1: Phrase(N) = 52 'S
Case "T"
N = N + 1: Phrase(N) = 81 'T
Case "U"
N = N + 1: Phrase(N) = 5 'UH
Case "V"
N = N + 1: Phrase(N) = 83 'V
Case "W"
N = N + 1: Phrase(N) = 85 'W
Case "X"
N = N + 1: Phrase(N) = 50 'KS
Case "Y"
N = N + 1: Phrase(N) = 11 'Y
Case "Z"
N = N + 1: Phrase(N) = 86 'Z
Case " "
'Do nothing
Case ","
N = N + 1: Phrase(N) = 128 'PAUSE1
Case "."
N = N + 1: Phrase(N) = 129 'PAUSE2
Case "?"
N = N + 1: Phrase(N) = 129 'PAUSE2
Case "!"
N = N + 1: Phrase(N) = 129 'PAUSE2
Case ";"
N = N + 1: Phrase(N) = 128 'PAUSE1
Case ":"
N = N + 1: Phrase(N) = 128 'PAUSE1
Case Else
'PRINT "Unknown character: "; MID$(word$, j, 1) 'Removed screen output
End Select
Next j
End If
If i <= Len(text) Then i = i + 1 'added this line
Loop
End Sub
' ----------------------------------------------------------------------
' Speech Generation Subroutine
' ----------------------------------------------------------------------
Sub GenerateSpeech ()
' Generate speech from the phoneme sequence in the Phrase array.
Dim i As Integer
Dim frequency As Integer
Dim duration As Integer
Dim amplitude As Integer
For i = 1 To N
frequency = Phoneme(Phrase(i)).frequency1
duration = Phoneme(Phrase(i)).duration
amplitude = Phoneme(Phrase(i)).amplitude
' Original SAM had screen output here.
PlaySound frequency, duration, amplitude
Next i
_Delay 200 ' Add a short delay after speaking, important for some sound cards.
End Sub
' ----------------------------------------------------------------------
' Sound Playback Subroutine
' ----------------------------------------------------------------------
Sub PlaySound (frequency As Integer, duration As Integer, amplitude As Integer)
' Generate a square wave sound. This is a simplified version
' of the sound generation. The original SAM used a more
' complex algorithm with filters and envelopes.
'
' QB64's SOUND function is used for sound output.
If frequency > 0 And amplitude > 0 Then ' Avoid trying to play silence or zero frequency.
Sound frequency, duration 'Plays the sound
End If
End Sub
' ----------------------------------------------------------------------
' Say Subroutine
' ----------------------------------------------------------------------
Sub Say (text As String)
' Wrapper function to simplify speech synthesis.
ParseText text
GenerateSpeech
End Sub
' ----------------------------------------------------------------------
' DATA Statements (Phoneme Data)
' ----------------------------------------------------------------------
' Phoneme data. Each line represents one phoneme and contains the
' following values:
'
' Frequency1, Frequency2, Amplitude, Duration, Inflection, Vowel,
' Pitch, Filter, Volume, Rate, Stress, Reserved
'
' The original SAM.BAS file had a large amount of data. It's included here
' in its entirety for completeness.
Data 160,160,32767,7,0,1,64,0,63,10,0,0
Data 260,260,32767,7,0,1,64,0,63,10,0,0
Data 294,294,32767,7,0,1,64,0,63,10,0,0
Data 247,247,32767,7,0,1,64,0,63,10,0,0
Data 220,220,32767,7,0,1,64,0,63,10,0,0
Data 208,208,32767,7,0,1,64,0,63,10,0,0
Data 311,311,32767,7,0,1,64,0,63,10,0,0
Data 277,277,32767,7,0,1,64,0,63,10,0,0
Data 330,330,32767,7,0,1,64,0,63,10,0,0
Data 311,311,32767,7,0,1,64,0,63,10,0,0
Data 370,370,32767,7,0,1,64,0,63,10,0,0
Data 392,392,32767,9,0,0,64,0,63,10,0,0
Data 440,440,32767,9,0,0,64,0,63,10,0,0
Data 494,494,32767,9,0,0,64,0,63,10,0,0
Data 523,523,32767,9,0,0,64,0,63,10,0,0
Data 587,587,32767,9,0,0,64,0,63,10,0,0
Data 659,659,32767,9,0,0,64,0,63,10,0,0
Data 698,698,32767,9,0,0,64,0,63,10,0,0
Data 784,784,32767,9,0,0,64,0,63,10,0,0
Data 880,880,32767,9,0,0,64,0,63,10,0,0
Data 988,988,32767,9,0,0,64,0,63,10,0,0
Data 1047,1047,32767,9,0,0,64,0,63,10,0,0
Data 1175,1175,32767,9,0,0,64,0,63,10,0,0
Data 1319,1319,32767,9,0,0,64,0,63,10,0,0
Data 1397,1397,32767,9,0,0,64,0,63,10,0,0
Data 1568,1568,32767,9,0,0,64,0,63,10,0,0
Data 1760,1760,32767,9,0,0,64,0,63,10,0,0
Data 1865,1865,32767,9,0,0,64,0,63,10,0,0
Data 2093,2093,32767,9,0,0,64,0,63,10,0,0
Data 2349,2349,32767,9,0,0,64,0,63,10,0,0
Data 2489,2489,32767,9,0,0,64,0,63,10,0,0
Data 160,160,32767,5,0,0,64,0,63,10,0,0
Data 160,160,32767,5,0,0,64,0,63,10,0,0
Data 160,160,32767,5,0,0,64,0,63,10,0,0
Data 160,160,32767,5,0,0,64,0,63,10,0,0
Data 349,349,32767,7,0,0,64,0,63,10,0,0
Data 175,175,32767,7,0,0,64,0,63,10,0,0
Data 196,196,32767,7,0,0,64,0,63,10,0,0
Data 233,233,32767,7,0,0,64,0,63,10,0,0
Data 277,277,32767,7,0,0,64,0,63,10,0,0
Data 311,311,32767,7,0,0,64,0,63,10,0,0
Data 349,349,32767,7,0,0,64,0,63,10,0,0
Data 415,415,32767,7,0,0,64,0,63,10,0,0
Data 466,466,32767,7,0,0,64,0,63,10,0,0
Data 523,523,32767,7,0,0,64,0,63,10,0,0
Data 587,587,32767,7,0,0,64,0,63,10,0,0
Data 622,622,32767,7,0,0,64,0,63,10,0,0
Data 698,698,32767,7,0,0,64,0,63,10,0,0
Data 784,784,32767,7,0,0,64,0,63,10,0,0
Data 830,830,32767,7,0,0,64,0,63,10,0,0
Data 932,932,32767,7,0,0,64,0,63,10,0,0
Data 1047,1047,32767,7,0,0,64,0,63,10,0,0
Data 1109,1109,32767,7,0,0,64,0,63,10,0,0
Data 1245,1245,32767,7,0,0,64,0,63,10,0,0
Data 1397,1397,32767,7,0,0,64,0,63,10,0,0
Data 1480,1480,32767,7,0,0,64,0,63,10,0,0
Data 1661,1661,32767,7,0,0,64,0,63,10,0,0
Data 1865,1865,32767,7,0,0,64,0,63,10,0,0
Data 1976,1976,32767,7,0,0,64,0,63,10,0,0
Data 2217,2217,32767,7,0,0,64,0,63,10,0,0
Data 2489,2489,32767,7,0,0,64,0,63,10,0,0
Data 2637,2637,32767,7,0,0,64,0,63,10,0,0
Data 2959,2959,32767,7,0,0,64,0,63,10,0,0
Data 3322,3322,32767,7,0,0,64,0,63,10,0,0
Data 3520,3520,32767,7,0,0,64,0,63,10,0,0
Data 3951,3951,32767,7,0,0,64,0,63,10,0,0
Data 160,160,32767,5,0,0,64,0,63,10,0,0
Data 247,247,32767,5,0,0,64,0,63,10,0,0
Data 294,294,32767,5,0,0,64,0,63,10,0,0
Data 220,220,32767,5,0,0,64,0,63,10,0,0
Data 311,311,32767,5,0,0,64,0,63,10,0,0
Data 370,370,32767,5,0,0,64,0,63,10,0,0
Data 440,440,32767,5,0,0,64,0,63,10,0,0
Data 494,494,32767,5,0,0,64,0,63,10,0,0
Data 587,587,32767,5,0,0,64,0,63,10,0,0
Data 659,659,32767,5,0,0,64,0,63,10,0,0
Data 784,784,32767,5,0,0,64,0,63,10,0,0
Data 880,880,32767,5,0,0,64,0,63,10,0,0
Data 1047,1047,32767,5,0,0,64,0,63,10,0,0
Data 1175,1175,32767,5,0,0,64,0,63,10,0,0
Data 1397,1397,32767,5,0,0,64,0,63,10,0,0
Data 1568,1568,32767,5,0,0,64,0,63,10,0,0
Data 1865,1865,32767,5,0,0,64,0,63,10,0,0
Data 2093,2093,32767,5,0,0,64,0,63,10,0,0
Data 2489,2489,32767,5,0,0,64,0,63,10,0,0
Data 2959,2959,32767,5,0,0,64,0,63,10,0,0
Data 160,160,20000,8,0,0,64,0,63,10,0,0
Data 160,160,20000,8,0,0,64,0,63,10,0,0
Data 261,261,20000,8,0,0,64,0,63,10,0,0
Data 174,174,20000,8,0,0,64,0,63,10,0,0
Data 196,196,20000,8,0,0,64,0,63,10,0,0
Data 233,233,20000,8,0,0,64,0,63,10,0,0
Data 277,277,20000,8,0,0,64,0,63,10,0,0
Data 311,311,20000,8,0,0,64,0,63,10,0,0
Data 349,349,20000,8,0,0,64,0,63,10,0,0
Data 415,415,20000,8,0,0,64,0,63,10,0,0
Data 466,466,20000,8,0,0,64,0,63,10,0,0
Data 523,523,20000,8,0,0,64,0,63,10,0,0
Data 587,587,20000,8,0,0,64,0,63,10,0,0
Data 622,622,20000,8,0,0,64,0,63,10,0,0
Data 698,698,20000,8,0,0,64,0,63,10,0,0
Data 784,784,20000,8,0,0,64,0,63,10,0,0
Data 830,830,20000,8,0,0,64,0,63,10,0,0
Data 932,932,20000,8,0,0,64,0,63,10,0,0
Data 1047,1047,20000,8,0,0,64,0,63,10,0,0
Data 1109,1109,20000,8,0,0,64,0,63,10,0,0
Data 1245,1245,20000,8,0,0,64,0,63,10,0,0
Data 1397,1397,20000,8,0,0,64,0,63,10,0,0
Data 1480,1480,20000,8,0,0,64,0,63,10,0,0
Data 1661,1661,20000,8,0,0,64,0,63,10,0,0
Data 1865,1865,20000,8,0,0,64,0,63,10,0,0
Data 1976,1976,20000,8,0,0,64,0,63,10,0,0
Data 2217,2217,20000,8,0,0,64,0,63,10,0,0
Data 2489,2489,20000,8,0,0,64,0,63,10,0,0
Data 2637,2637,20000,8,0,0,64,0,63,10,0,0
Data 2959,2959,20000,8,0,0,64,0,63,10,0,0
Data 3322,3322,20000,8,0,0,64,0,63,10,0,0
Data 3520,3520,20000,8,0,0,64,0,63,10,0,0
Data 3951,3951,20000,8,0,0,64,0,63,10,0,0
Data 160,160,20000,5,0,0,64,0,63,10,0,0
Data 247,247,20000,5,0,0,64,0,63,10,0,0
Data 294,294,20000,5,0,0,64,0,63,10,0,0
Data 220,220,20000,5,0,0,64,0,63,10,0,0
Data 311,311,20000,5,0,0,64,0,63,10,0,0
Data 370,370,20000,5,0,0,64,0,63,10,0,0
Data 440,440,20000,5,0,0,64,0,63,10,0,0
Data 494,494,20000,5,0,0,64,0,63,10,0,0
Data 587,587,20000,5,0,0,64,0,63,10,0,0
Data 659,659,20000,5,0,0,64,0,63,10,0,0
Data 784,784,20000,5,0,0,64,0,63,10,0,0
Data 880,880,20000,5,0,0,64,0,63,10,0,0
Data 1047,1047,20000,5,0,0,64,0,63,10,0,0
Data 1175,1175,20000,5,0,0,64,0,63,10,0,0
Data 1397,1397,20000,5,0,0,64,0,63,10,0,0
Data 1568,1568,20000,5,0,0,64,0,63,10,0,0
Data 1865,1865,20000,5,0,0,64,0,63,10,0,0
Data 2093,2093,20000,5,0,0,64,0,63,10,0,0
Data 2489,2489,20000,5,0,0,64,0,63,10,0,0
Data 2959,2959,20000,5,0,0,64,0,63,10,0,0
Data 160,160,32767,7,0,0,64,0,63,10,0,0
Data 170,170,32767,7,0,0,64,0,63,10,0,0
Data 160,160,32767,7,0,0,64,0,63,10,0,0
Data 170,170,32767,7,0,0,64,0,63,10,0,0
Data 181,181,32767,7,0,0,64,0,63,10,0,0
Data 192,192,32767,7,0,0,64,0,63,10,0,0
Data 204,204,32767,7,0,0,64,0,63,10,0,0
Data 216,216,32767,7,0,0,64,0,63,10,0,0
Data 230,230,32767,7,0,0,64,0,63,10,0,0
Data 244,244,32767,7,0,0,64,0,63,10,0,0
Data 259,259,32767,7,0,0,64,0,63,10,0,0
Data 275,275,32767,7,0,0,64,0,63,10,0,0
Data 292,292,32767,7,0,0,64,0,63,10,0,0
Data 310,310,32767,7,0,0,64,0,63,10,0,0
Data 329,329,32767,7,0,0,64,0,63,10,0,0
Data 349,349,32767,7,0,0,64,0,63,10,0,0
Data 370,370,32767,7,0,0,64,0,63,10,0,0
Data 392,392,32767,7,0,0,64,0,63,10,0,0
Data 415,415,32767,7,0,0,64,0,63,10,0,0
Data 440,440,32767,7,0,0,64,0,63,10,0,0
Data 466,466,32767,7,0,0,64,0,63,10,0,0
Data 494,494,32767,7,0,0,64,0,63,10,0,0
Data 523,523,32767,7,0,0,64,0,63,10,0,0
Data 554,554,32767,7,0,0,64,0,63,10,0,0
Data 587,587,32767,7,0,0,64,0,63,10,0,0
Data 622,622,32767,7,0,0,64,0,63,10,0,0
Data 659,659,32767,7,0,0,64,0,63,10,0,0
Data 698,698,32767,7,0,0,64,0,63,10,0,0
Data 740,740,32767,7,0,0,64,0,63,10,0,0
Data 784,784,32767,7,0,0,64,0,63,10,0,0
Data 830,830,32767,7,0,0,64,0,63,10,0,0
Data 880,880,32767,7,0,0,64,0,63,10,0,0
Data 932,932,32767,7,0,0,64,0,63,10,0,0
Data 988,988,32767,7,0,0,64,0,63,10,0,0
Data 1047,1047,32767,7,0,0,64,0,63,10,0,0
Data 1109,1109,32767,7,0,0,64,0,63,10,0,0
Data 1175,1175,32767,7,0,0,64,0,63,10,0,0
Data 1245,1245,32767,7,0,0,64,0,63,10,0,0
Data 1319,1319,32767,7,0,0,64,0,63,10,0,0
Data 1397,1397,32767,7,0,0,64,0,63,10,0,0
Data 1480,1480,32767,7,0,0,64,0,63,10,0,0
Data 1568,1568,32767,7,0,0,64,0,63,10,0,0
Data 1661,1661,32767,7,0,0,64,0,63,10,0,0
Data 1760,1760,32767,7,0,0,64,0,63,10,0,0
Data 1865,1865,32767,7,0,0,64,0,63,10,0,0
Data 1976,1976,32767,7,0,0,64,0,63,10,0,0
Data 2093,2093,32767,7,0,0,64,0,63,10,0,0
Data 2217,2217,32767,7,0,0,64,0,63,10,0,0
Data 2349,2349,32767,7,0,0,64,0,63,10,0,0
Data 2489,2489,32767,7,0,0,64,0,63,10,0,0
Data 2637,2637,32767,7,0,0,64,0,63,10,0,0
Data 2794,2794,32767,7,0,0,64,0,63,10,0,0
Data 2959,2959,32767,7,0,0,64,0,63,10,0,0
Data 3136,3136,32767,7,0,0,64,0,63,10,0,0
Data 3322,3322,32767,7,0,0,64,0,63,10,0,0
Data 3520,3520,32767,7,0,0,64,0,63,10,0,0
Data 3729,3729,32767,7,0,0,64,0,63,10,0,0
Data 3951,3951,32767,7,0,0,64,0,63,10,0,0
' Phoneme names corresponding to the data above.
Data "AH","AO","AA","AE","EH","ER","IH","EY","IY","AY","UH","UW","UX","OH","OY","AX","AXR","AW","AWH","OW","P","B","T","D","K","G","CH","JH","S","Z","SH","ZH","F","V","TH","DH","M","N","NG","L","R","W","Y","H","PAUSE","BEEP","BREATH","UH","AH","IH","EH","OH","UW","P","T","K","F","TH","S","SH","H","M","N","L","R","W","Y","B","D","G","V","DH","Z","ZH","CH","JH","NG","BREATH","UH","AH","IH","EH","OH","UW","P","T","K","F","TH","S","SH","H","M","N","L","R","W","Y","B","D","G","V","DH","Z","ZH","CH","JH","NG","PAUSE1","PAUSE2","PUNC"
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN 'fnc2.bi' INCLUDE
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' $Id: fnc.bi,v 1.3 2011/03/19 17:44:48 Steve Exp $
'
' QB64 Function Library Header File
' --------------------------------
' This header file provides a set of commonly used functions for QB64
' programming. It includes functions for string manipulation,
' input/output, and other general-purpose tasks.
'
' Functions Included
' ------------------
' TRIM$ - Removes leading and trailing spaces from a string.
' LTRIM$ - Removes leading spaces from a string.
' RTRIM$ - Removes trailing spaces from a string.
' MTRIM$ - Removes extra spaces between words in a string.
' ISNULL - Checks if a string is NULL (empty).
' DEFAULT$ - Returns a default value if a string is NULL.
' CHOP$ - Removes a specified number of characters from the end of a string.
' STRREV$ - Reverses a string.
' PAD$ - Pads a string to a specified length with a character.
' PADL$ - Pads a string on the left.
' PADR$ - Pads a string on the right.
' SPLIT% - Splits a string into an array of substrings based on a delimiter.
' JOIN$ - Joins an array of strings into a single string with a delimiter.
' PROPER$ - Converts a string to proper case (first letter of each word capitalized).
' WORDCOUNT - Counts the number of words in a string.
' INSTRREV - Finds the last occurrence of a substring within a string.
' FILEXISTS - Checks if a file exists.
' DIR$ - Returns a list of files matching a specified pattern.
' INPUTSTR$ - Reads a specified number of characters from a file.
' REPLACEN$ - Replaces occurrences of a substring within a string, with a limit.
' PARSE - Parses a string based on delimiters and returns an array.
' ARRAYSIZE - Returns the number of elements in an array.
' LCASE$ - Converts a string to lower case
' UCASE$ - Converts a string to upper case
'
' Notes
' -----
' - This file should be included in your QB64 programs using the
' '$INCLUDE: 'fnc.bi' directive. Make sure fnc.bi is in the same directory
' as your .BAS file, or in a directory specified in the QB64 include path.
' - These functions are designed to provide functionality similar to
' functions found in other programming languages, making it easier to
' perform common tasks in QB64.
' - Some functions are named differently than their equivalent QB64
' functions (e.g., MTRIM$ instead of LTRIM$(RTRIM$())) to provide
' more intuitive names.
'
' Example
' -------
' '$INCLUDE: 'fnc.bi'
'
' DIM text AS STRING
' text = " Hello, World! "
' PRINT "Original: '" + text + "'"
' PRINT "TRIM$: '" + TRIM$(text) + "'"
' PRINT "LTRIM$: '" + LTRIM$(text) + "'"
' PRINT "RTRIM$: '" + RTRIM$(text) + "'"
' PRINT "MTRIM$: '" + MTRIM$(text) + "'"
'
' DIM filename AS STRING
' filename = "myfile.txt"
' IF FILEEXISTS(filename) THEN
' PRINT filename + " exists."
' ELSE
' PRINT filename + " does not exist."
' END IF
'
' ' ... other function examples ...
' Function Declarations
'DECLARE FUNCTION TRIM$ (text AS STRING)
'DECLARE FUNCTION LTRIM$ (text AS STRING)
'DECLARE FUNCTION RTRIM$ (text AS STRING)
'DECLARE FUNCTION MTRIM$ (text AS STRING)
'DECLARE FUNCTION ISNULL (text AS STRING)
'DECLARE FUNCTION DEFAULT$ (text AS STRING, default_value AS STRING)
'DECLARE FUNCTION CHOP$ (text AS STRING, num_chars AS INTEGER)
'DECLARE FUNCTION STRREV$ (text AS STRING)
'DECLARE FUNCTION PAD$ (text AS STRING, length AS INTEGER, pad_char AS STRING)
'DECLARE FUNCTION PADL$ (text AS STRING, length AS INTEGER, pad_char AS STRING)
'DECLARE FUNCTION PADR$ (text AS STRING, length AS INTEGER, pad_char AS STRING)
'DECLARE FUNCTION SPLIT% (text AS STRING, delimiter AS STRING, result_array$() AS STRING) AS INTEGER
'DECLARE FUNCTION JOIN$ (text_array$() AS STRING, delimiter AS STRING) AS STRING
'DECLARE FUNCTION PROPER$ (text AS STRING)
'DECLARE FUNCTION WORDCOUNT (text AS STRING) AS INTEGER
'DECLARE FUNCTION INSTRREV (text AS STRING, substring AS STRING, start_position AS INTEGER) AS INTEGER
'DECLARE FUNCTION FILEXISTS (filename AS STRING) AS INTEGER
'DECLARE FUNCTION DIR$ (pathname AS STRING) AS STRING
'DECLARE FUNCTION INPUTSTR$ (filenumber AS INTEGER, num_chars AS INTEGER) AS STRING
'DECLARE FUNCTION REPLACEN$ (text AS STRING, search_string AS STRING, replace_string AS STRING, max_replacements AS INTEGER) AS STRING
'DECLARE FUNCTION PARSE (text AS STRING, delimiters AS STRING, parsed_array$() AS STRING) AS INTEGER
'DECLARE FUNCTION ARRAYSIZE (any_array AS Variant) AS INTEGER
'DECLARE FUNCTION LCASE$ (text AS STRING) AS STRING
'DECLARE FUNCTION UCASE$ (text AS STRING) AS STRING
' ----------------------------------------------------------------------
' Function Implementations
' ----------------------------------------------------------------------
Function TRIM$ (text As String)
' Removes leading and trailing spaces from a string.
TRIM$ = LTrim$(RTrim$(text))
End Function
'FUNCTION LTRIM$ (text AS STRING)
' ' Removes leading spaces from a string.
' DIM i AS INTEGER
' i = 1
' DO WHILE i <= LEN(text) AND MID$(text, i, 1) = " "
' i = i + 1
' LOOP
' LTRIM$ = MID$(text, i)
'END FUNCTION
'
'FUNCTION RTRIM$ (text AS STRING)
' ' Removes trailing spaces from a string.
' DIM i AS INTEGER
' i = LEN(text)
' DO WHILE i >= 1 AND MID$(text, i, 1) = " "
' i = i - 1
' LOOP
' RTRIM$ = LEFT$(text, i)
'END FUNCTION
Function MTRIM$ (text As String)
' Removes extra spaces between words in a string, leaving only one space.
Dim result As String
Dim i As Integer
Dim previous_char As String
result = ""
previous_char = ""
For i = 1 To Len(text)
If Mid$(text, i, 1) <> " " Then
result = result + Mid$(text, i, 1)
previous_char = Mid$(text, i, 1)
ElseIf previous_char <> " " Then
result = result + " "
previous_char = " "
End If
Next i
MTRIM$ = TRIM$(result) ' Use TRIM$ to remove leading/trailing spaces as well.
End Function
Function ISNULL% (text As String)
' Checks if a string is NULL (empty).
ISNULL = (text = "")
End Function
Function DEFAULT$ (text As String, default_value As String)
' Returns a default value if a string is NULL.
If ISNULL(text) Then
DEFAULT$ = default_value
Else
DEFAULT$ = text
End If
End Function
Function CHOP$ (text As String, num_chars As Integer)
' Removes a specified number of characters from the end of a string.
If num_chars >= Len(text) Then
CHOP$ = ""
Else
CHOP$ = Left$(text, Len(text) - num_chars)
End If
End Function
Function STRREV$ (text As String)
' Reverses a string.
Dim result As String
Dim i As Integer
result = ""
For i = Len(text) To 1 Step -1
result = result + Mid$(text, i, 1)
Next i
STRREV$ = result
End Function
Function PAD$ (text As String, length As Integer, pad_char As String)
' Pads a string to a specified length with a character.
' Pads on the right by default.
PAD$ = PADR$(text, length, pad_char)
End Function
Function PADL$ (text As String, length As Integer, pad_char As String)
' Pads a string on the left to a specified length with a character.
Dim padding As String
Dim i As Integer
padding = ""
If Len(pad_char) = 0 Then pad_char = " " ' Default padding character
For i = 1 To length - Len(text)
padding = padding + Left$(pad_char, 1)
Next i
PADL$ = padding + text
End Function
Function PADR$ (text As String, length As Integer, pad_char As String)
' Pads a string on the right to a specified length with a character.
Dim padding As String
Dim i As Integer
padding = ""
If Len(pad_char) = 0 Then pad_char = " " ' Default padding character.
For i = 1 To length - Len(text)
padding = padding + Left$(pad_char, 1)
Next i
PADR$ = text + padding
End Function
Function SPLIT% (text As String, delimiter As String, result_array$())
' Splits a string into an array of substrings based on a delimiter.
' Returns the number of elements in the array.
Dim i As Integer
Dim start_pos As Integer
Dim end_pos As Integer
Dim count As Integer
start_pos = 1
count = 0
ReDim result_array$(0) ' Initialize the array
If delimiter = "" Then
'Handle empty delimiter
result_array$(0) = text
SPLIT% = 1
Exit Function
End If
Do
end_pos = InStr(start_pos, text, delimiter)
If end_pos = 0 Then
' Last substring
count = count + 1
ReDim _Preserve result_array$(count - 1)
result_array$(count - 1) = Mid$(text, start_pos)
Exit Do
Else
' Extract substring
count = count + 1
ReDim _Preserve result_array$(count - 1)
result_array$(count - 1) = Mid$(text, start_pos, end_pos - start_pos)
start_pos = end_pos + Len(delimiter)
End If
Loop
SPLIT% = count
End Function
Function JOIN$ (text_array$(), delimiter As String)
' Joins an array of strings into a single string with a delimiter.
Dim result As String
Dim i As Integer
result = ""
For i = LBound(text_array$) To UBound(text_array$)
result = result + text_array$(i)
If i < UBound(text_array$) Then
result = result + delimiter
End If
Next i
JOIN$ = result
End Function
Function PROPER$ (text As String)
' Converts a string to proper case (first letter of each word capitalized).
Dim result As String
Dim i As Integer
Dim capitalize As Integer
result = ""
capitalize = -1 ' Start with -1 to capitalize the first letter
For i = 1 To Len(text)
If Mid$(text, i, 1) = " " Then
capitalize = -1
result = result + " "
ElseIf capitalize Then
result = result + UCase$(Mid$(text, i, 1))
capitalize = 0
Else
result = result + LCase$(Mid$(text, i, 1))
End If
Next i
PROPER$ = result
End Function
Function WORDCOUNT% (text As String)
' Counts the number of words in a string.
Dim count As Integer
Dim i As Integer
Dim previous_char As String
count = 0
previous_char = " "
For i = 1 To Len(text)
If Mid$(text, i, 1) <> " " And previous_char = " " Then
count = count + 1
End If
previous_char = Mid$(text, i, 1)
Next i
WORDCOUNT = count
End Function
Function INSTRREV% (text As String, substring As String, start_position As Integer)
' Finds the last occurrence of a substring within a string,
' starting from a specified position.
Dim i As Integer
If start_position = 0 Then start_position = Len(text)
For i = start_position To 1 Step -1
If Left$(Mid$(text, i), Len(substring)) = substring Then
INSTRREV = i
Exit Function
End If
Next i
INSTRREV = 0
End Function
Function FILEXISTS% (filename As String)
' Checks if a file exists.
Dim file_attr As Long
file_attr = _FileExists(filename)
If file_attr Then
FILEEXISTS = -1 ' TRUE
Else
FILEEXISTS = 0 ' FALSE
End If
End Function
Function DIR$ (pathname As String)
' Returns a list of files matching a specified pattern.
' This is a wrapper around the QB64 DIR$ function.
DIR$ = _Dir$(pathname)
End Function
'Function INPUTSTR$ (filenumber As Integer, num_chars As Integer)
' ' Reads a specified number of characters from a file.
' INPUTSTR$ = String$(num_chars, 0) 'pre-allocate
' GET filenumber, , INPUTSTR$
'End Function
Function REPLACEN$ (text As String, search_string As String, replace_string As String, max_replacements As Integer)
' Replaces occurrences of a substring within a string, with a limit.
Dim position As Integer
Dim result As String
Dim count As Integer
result = ""
count = 0
position = 1
If max_replacements = 0 Then max_replacements = -1 ' -1 for unlimited
If search_string = "" Then
REPLACEN$ = text
Exit Function
End If
Do
position = InStr(position, text, search_string)
If position = 0 Or (count >= max_replacements And max_replacements <> -1) Then
result = result + Mid$(text, position)
Exit Do
Else
result = result + Mid$(text, position - 1) + replace_string
position = position + Len(search_string)
count = count + 1
End If
Loop
REPLACEN$ = result
End Function
Function PARSE% (text As String, delimiters As String, parsed_array$())
' Parses a string based on delimiters and returns an array of the parsed strings.
' Returns the number of elements in the array.
Dim i As Integer
Dim start_pos As Integer
Dim end_pos As Integer
Dim count As Integer
Dim found As Integer
start_pos = 1
count = 0
ReDim parsed_array$(0) ' Initialize the array
If delimiters = "" Then
parsed_array$(0) = text
PARSE = 1
Exit Function
End If
Do
end_pos = 0
found = 0
For i = start_pos To Len(text)
If InStr(1, delimiters, Mid$(text, i, 1)) Then
end_pos = i
found = -1
Exit For
End If
Next i
If end_pos = 0 Then end_pos = Len(text) + 1
count = count + 1
ReDim _Preserve parsed_array$(count - 1)
parsed_array$(count - 1) = Mid$(text, start_pos, end_pos - start_pos)
start_pos = end_pos + 1
Loop Until start_pos > Len(text)
PARSE = count
End Function
'FUNCTION ARRAYSIZE% (any_array AS Variant)
' ' Returns the number of elements in an array.
' ' Works for both fixed and dynamic arrays.
' ' Returns -1 if the variable is not an array.
' IF ISARRAY(any_array) THEN
' ARRAYSIZE = UBOUND(any_array) - LBOUND(any_array) + 1
' ELSE
' ARRAYSIZE = -1
' END IF
'END FUNCTION
'FUNCTION LCASE$ (text AS STRING)
' LCASE$ = LCASE(text)
'END FUNCTION
'FUNCTION UCASE$ (text AS STRING)
' UCASE$ = UCASE(text)
'END FUNCTION
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END 'fnc2.bi' INCLUDE
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++