| Home CBM ASCII-X BASIC C128 2MHz Border BASIC 7.80 BASIC 8 CPM Digimaster 128 Fast Serial for uIEC Games Interlace JiffySoft128 Keyboard Scan Media Player 128 Orig Interlace RGBI to S-Video RGBI to SCART RGBI to VGA RGB Conversion SAM 128 Alpha Long Common Phonemes Reciter SAM Technical SID Player 128 VDC Interlace Mp128alpha N-progs D64plus Disk Escape Codes Hardware PCxface PETSCII Pet2asc Futurama IBM PC-AT Contact Games Glossary Hall of fame Hall of shame Miscellaneous Privacy policy Programming Twisty puzzles |
The BASIC-Wedge commands are easy to spot because they all must be entered with a leading close-bracket "]". The pages discussing SAM and Reciter generally don't include this leading bracket for ease-of-reading (unless an example is given to be entered). The above list gives a brief description of each, and the next few paragraphs talks about the syntax they use. More detailed information about these commands can be found in other sections (referenced in the following paragraphs). Like the original C64 version of SAM, commands may be abbreviated by omitting letters from the end, as long as there is no ambiguity. For example, you may type ]ERR (or simply ]E) instead of typing out ]ERROR in full. However, you may not abbreviate ]SAY with ]SA because that might also refer to ]SAM. Some of the BASIC-Wedge commands use no arguments (CPUFIX, ERROR, PHONES, QUIT, RECITER, SAM). If you are not using the BASIC Wedge, you will need to SYS a special address which is specific to the desired command (see the section Common ML Routines, below). Of these, CPUFIX and PHONES are unique to the C128 port of SAM. Note: if you did not load Reciter 128 (i.e., you loaded SAM128.BIN instead), then ]RECITER will not do anything (silent failure).Many of the BASIC-Wedge commands take one or two numeric arguments (KNOBS, LIGHTS, NOISES, PITCH, SPEED, TIMEBASE). For all of them, a non-numeric (string) argument will cause a TYPE MISMATCH ERROR. For all of them, floating-point values will be converted to integers as if the BASIC INT() function had been used. With one exception (TIMEBASE), the numeric value must be in the range of 0 to 255, or an ILLEGAL QUANTITY ERROR will occur (for TIMEBASE, the value must be in the range 0 to 65535). A value of 0 is silently ignored in all of these commands, except LIGHTS. The argument to LIGHTS is Boolean: zero means false (don't show the VIC screen) and any other legal number is true (show the VIC screen). If you are not using the BASIC Wedge, all of these commands can be accessed with a single SYS address (see the section Poker, below). Of these, NOISES and TIMEBASE are unique to the C128 port of SAM. The KNOBS (and NOISES) command may take up to 2 arguments. You may also omit one of the arguments (in which case, the previous value will remain in effect). You may not omit both arguments (this will cause a SYNTAX ERROR). Examples: ]KNOBS , 64 :REM omit first argument ]KNOBS 92 :REM omit second argument
To use the BASIC Wedge, you first need to install either SAM or Reciter (see the SAM 128 page for details). Then you load WEDGE.BIN into Bank 1 RAM. In BASIC you would do something like this: BLOAD"WEDGE.BIN",U8,B1 which loads the file into Bank 1 at address 16384 ($4000). Next call the install routine at $4000; in BASIC you would write something like: BANK 1: SYS 16384 The install routine will first look at the current end-of-strings pointer for BASIC. This will be the start of SAM/Reciter if used just installed that. Then it subtracts the amount of memory it needs to run (or a little more, to ensure page alignment) to get a new (lower) end-of-strings. The current Wedge uses 768 bytes (0.75 KB). Next, code is relocated to the new address. Finally the BASIC pointers are updated to reflect the reduced amount of memory available. Note: the final step effectively erases all BASIC variables! Besides being in a separate module, there is one other important difference in the way the BASIC Wedge in the C128 version works (compared to the original C64 version). The "iError" vector is redirected, instead of replacing the "CharGet" routine. For ML hackers, this is mainly trivia, but for BASIC users, this change brings some nice benefits, one annoying incompatibility, and one "be careful" ("gotcha") issue. The benefits of the C128 Wedge (versus C64) are:
The one annoying incompatibility is you must use ]SAY in the C128 Wedge. On the C64, you could simply use SAY. This is not a big deal when writing new programs, but is annoying when you want to port an existing program. I considered several ways to get the C64 behavior, but they would either be slow (CharGet replacement) or would require a lot of text re-scanning and other tricks (which is slow to execute and consumes more memory). I believe the benefits outweigh the cost of "not 100% portable". Also, because the C64 version doesn't allow variables or expressions for numeric arguments, any SAM program that wants to dynamically change PITCH or SPEED (for example) must rely on POKEs instead, which makes the C64 version "non-portable" to begin with (a priori). ]SPEED D1 but if you a tried to abbreviate this like]SPEE D1 then it would (generally) fail because it would be interpreted as]SPEED 1 (note there is no variable, only a constant!)The above was an arbitrary example of how things can go wrong. You can probably imagine many other ways. So be careful with abbreviations (or better: don't use them). If something acts weird with abbreviations, this may be the issue.
For ML programmers, you will find a jump table beginning at $EE00 (the dictionary is only present if you load Reciter): .EE00 JMP Install ;clears BASIC variables! .EE03 JMP Remove ;clears BASIC variables! .EE06 JMP SayItBASIC .EE09 JMP SayIt .EE0C JMP ReSyBASIC ;only if you loaded Reciter 128 .EE0F JMP Reciter ;only if you loaded Reciter 128 .EE12 JMP Poker ;KNOBS, LIGHTS, NOISES, PITCH, SPEED, TIMEBASE .EE15 JMP DspErr ;ERROR .EE18 JMP Peeker .EE1B JMP DspPhones ;PHONES .EE1E JMP CPUfix ;adjust TIMEBASE and NOISES per CPU speed and NTSC/PAL .EE21 BIT samStr ;location of input string/buffer .EE24 BIT dicAlphaLo ;location of Dictionary index (index A -> start of dictionary) .EE27 BIT ChrTab ;location of Dictionary character classification table .EE2A JSR WrFarCall ;install temporary cross-bank routine in Common RAM Note that 3 of the last 4 entries (those with a BIT opcode) are not routines which a programmer may call. Each simply references an important memory location that a programmer might need. If the dictionary is not present (you loaded SAM instead of Reciter), then the last two BIT entries will refer to address zero. The Install routine at 60928 ($EE00) might be considered a common routine, depending on how liberal your definitions are! Conceptually it operates the same for both SAM and Reciter. In reality, the Reciter version will reserve more memory (leave less BASIC variable space free to use). One common routine, which is very simple, is the Remove (uninstall) routine at 60931 ($EE03). This just resets BASIC's variables so that all RAM in Bank 1 (up to $FF00) is available to BASIC. Warning: if you installed the BASIC-Wedge, be sure to use its ]QUIT command; otherwise, the wedge will remain active, but BASIC variables can start destroying SAM code, which will eventually cause a system crash! Technically speaking, the two main SAM routines, SayItBASIC at 60934 ($EE06) and SayIt at 60937 ($EE09), are common routines (you can call SAM even if you did not load Reciter 128). For more details on these, refer to the SAM page. In contrast, the two main Reciter routines, ReSyBASIC at 60940 ($EE0C) and Reciter at 60943 ($EE0F) are unique (not common). For details of them, refer to the Reciter page. Note: if you load SAM (instead of Reciter), calling those routines will do nothing (silent failure). The DspErr routine (ERROR) at 60949 ($EE15) is most useful when using SAM (see the SAM page), but may also be useful with Reciter to see how your English text was converted into phonemes (see the Reciter page). The DspPhones routine (PHONES) at 60955 ($EE1B) is most useful to the SAM programmer. It shows how the input phoneme text was "exploded" into sub-phonemes ("phones") along with the application of internal stress rules and phrase breaks. See the SAM page for details. Can also be used after loading Reciter, but is mainly a curiosity since you can't specify phonetic text (unless you switch to SAM-Mode).
CPUFIX does not make changes to settings that are due to software differences; thus it does not directly modify things like KNOBS, PITCH, and SPEED. The idea is you can take a C64/NTSC program with custom KNOBS/PITCH/SPEED settings (or even the default settings), and run them on the C128 with any hardware and hear the same thing. This also implies you can take a C128-Version program with custom speech settings and run them on different C128 hardware and get the same sound. CPUFIX is automatically called once: when you install SAM 128 or Reciter 128. If you later change settings (for example, switch the CPU speed from SLOW / 1MHz to FAST / 2MHz) then you will need to manually call CPUFIX. I was temped to have the CPUFIX called every time that SAM / Reciter is called to speak, but decided not to do so because CPUFIX will (most importantly) destroy any custom settings to NOISES and TIMEBASE, and it will slow things down a tiny bit (should not be human-noticeable). See below for more info about NOISES and TIMEBASE. For example, without a SuperCPU, but with Reciter 128 and the BASIC Wedge installed: SLOW:]CPUFIX ]SAY "VOICE TEST." FAST:]CPUFIX ]SAY "VOICE TEST." SAM (or rather Reciter) should sound the same in both cases. Repeat the above example after removing both instances of ]CPUFIX (you should hear a dramatic difference).
The most versatile of the common routines is what I call Poker at 60946 ($EE12). This changes various settings used directly by SAM (and indirectly by Reciter). Just call the routine with an 'address value' (where to poke) and one or two values to be used (what to poke). With the BASIC-Wedge, these can be accessed with custom BASIC keywords. Those are listed below, for your information. Trivia: two new entries are exclusive to my C128 version (NOISES and TIMEBASE).
For example, to make SAM speak a little faster than normal, you need to change the SPEED (at 'address' 4) to a value less than 72 (let's say 66). In BASIC you can do it (without using the Wedge) like this: SYS 60946,4,66 assuming that BANK 1 is already in effect. To use Poker from ML, just load the A, X, and Y registers with the values indicated in the table and then call the routine. To repeat (translate) the previous example, do this: LDA #4 ;poke 'Address' 4 (SPEED) LDX #1 ;value to set JSR $EE12 ;call Poker directly (only if running in BANK 1 -- otherwise use FAR_CALL)
The important thing to know is that the first two formants are sine waves and the third is a square wave. The first "knob" value applies to the first sine wave ("mouth") while the second value applies to the other sine wave ("throat"). There is no way to manipulate the square waveform (I imagine this refers to "lips/tongue", but who knows?). Changing KNOBS will adjust the relative frequency (pitch) of the following phonemes:
As you can see most of the affected phonemes are vowels or approximants (R,L,W,Y). Also included are the nasal sounds M,N,NX. Strangely, the "mixed D-T" phoneme DX is also affected (I guess because SAM will automatically create this phoneme when T or D is surrounded by vowels). KNOBS acts similar to PITCH, but there are three main differences:
The relative frequency set by KNOBS is the given value divided by 128. So a value of 128 will set a relative frequency of 128/128 = 1.0 (i.e., the default / normal value). A value of 64 will set a relative frequency of 64/128 = 0.5 (i.e., half the default frequency = lower tone). A value of 255 will set the relative frequency at 255/128 = 1.9921875 (i.e., almost double the default frequency = higher tone). Technical note: the absolute frequency will be relative to the phoneme's base frequency (6536 Hz / [global PITCH + phoneme's stress_relative_wavelength])... and the magic value of 6536 assumes you are using the correct TIMEBASE for your CPU. And if you wonder why PITCH appears in the denominator of the above equation (and is added to a wavelength), it is because the PITCH setting is really wavelength (not frequency).
The important thing to know is NOISES changes the time-base for two sets of 'noisy' phonemes (called X and Y for lack of better names), which changes both the pitch and speed of the phonemes. The default values are 7 and 6 (intended for NTSC at 1MHz -- see also CPUFIX). Greater values will result in slower speed and lower pitch (compared to default speech), and should be used if the CPU is set to FAST / 2MHz speed (or SuperCPU / 20MHz speed). The affected phonemes are:
As described under the "common" list of phonemes, SAM will internally expand some phonemes into 2 or 3 sub-phonemes (for lack of a better term... phone would be right for some, but not all). The NOISES value only affects part 2 (and not all expanded phonemes, just those shown above) -- hence the tables include non-standard "phonemes" like CH.2. From a phonetic (linguistic) point of view, NOISES applies to the fricatives (including the psudo-fricative H sounds), the affricates (CH and J), and two plosives (P and T). You don't strictly need to know, but SAM has five separate PCM tables. Different "noisy" phonemes use different PCM tables; tables 1 to 3 are shared by multiple phonemes, while tables 4 and 5 are each used by a single phoneme. You also don't really need to know the duration value, but hopefully you will find it educational. The "duration" is the number of bytes that will be read from the PCM table, and each byte (8 bits) represents 8 PCM samples to play (each bit is rendered with a fixed amplitude for that (sub)phoneme). Both amplitude values are fixed for the voiced phonemes, although their duration is variable. For the unvoiced ones, the duration is fixed while the amplitude high varies by PCM table (amplitude low is fixed). The "Value X Phonemes" are what I think of as "pure noise". They include all "rushing" phonemes, part 2 of the affricate CH, and part 2 of the plosives P and T. All are classified as "unvoiced". I call them "pure noise" because when SAM renders them, he completely skips the normal 3-formant code and immediately plays a fixed number of samples from the indicated PCM table. This means the normal affects of PITCH, SPEED, TIMEBASE, and internal amplitude are completely ignored. Also the duration of each is fixed, and relatively long. See my Technical page for details. Included under the "Value X Phonemes" is the undocumented phoneme * (asterisk). This is simply the second sub-phone of "CH". Hence it appears on the same row as CH.2. The "Value Y phonemes" are what I call "voicey noise". They include the fricatives (Z, ZH, V, DH), and part 2 of the affricate J. These are all classified as "voiced". These phonemes work differently than the "pure noise" ones. For these, SAM begins playing the phoneme using the normal 3-formant algorithm. This means they are affected by PITCH, SPEED, TIMEBASE, and the internal amplitude. However, after 75% of the phoneme's base wavelength has been rendered, SAM will switch to a PCM playback routine. The duration of the PCM-part of the phoneme is very short (compared to those of the X-Values). This is because 75% of the waveform has already been played. The duration is not fixed for each phoneme; it is calculated as base wavelength / 16 + 1 (see the section on PITCH to learn more).. Again, the duration tells the number of bytes to read from the PCM table and playback. And although the amplitude of each bit is again fixed, different values are used than with the "pure noise" (Value X phonemes). See my Technical page for details. Technical note (okay to ignore): assuming the CPU is running at exactly 1.00 MHz, the "X-Phonemes" have a 17.4 kHz (sample) bit rate, while the "Y-Phonemes" have a 19.2 kHz bit rate. It is not known if the audio samples were actually captured at these (or similar) two rates, or more likely (my opinion) the difference is sloppy programming (i.e., the samples were captured at one single rate, but coding differences made playback rates differ). The code uses simple 'bit-banging' of the SID volume register which does not allow SID's internal filters to affect the audio. However, analog circuits in C128 audio output (and possibly in your TV/monitor/speakers) will low-pass filter the audio. I don't think it is possible to accurately describe the filtering due to all the unknown variables. Each table contains a different mixture of high and low frequencies. It would be interesting to do a spectral analysis on them... As some practical examples you can use SYS 60946,2,18,16 to change the NOISE setting for 2MHz (FAST) CPU speed (NTSC), or you can use SYS 60946,2,7,6 to restore the NOISE setting to the default 1MHz (SLOW) CPU speed. Both examples assume that BANK 1 is already in effect.
Values lower than about 32 or greater than about 115 may cause erroneous output (depends on stress of phonemes). Logically (the way I'm thinking) PITCH values up to 243 should be okay, but it seems there is a bug in SAM for effective pitch values around 128 (I need to research). With the default PITCH value of 64, a phoneme with stress-1 (greatest stress) will have half the fundamental wavelength (double the frequency) of an unstressed phoneme. (Note this stres-1 = double frequency relation is not true with other PITCH values). If my calculations are correct, the fundamental wavelength (really time period) is approximately 153 microseconds times the effective value (PITCH + delta wavelength). Thus, SAM's default wavelength is 9.792 ms (which is a frequency of 102 Hz). Or in other words, the fundamental frequency of a typical phoneme is about 6536 Hz divided by the effective pitch. (The calculations assume the recommended TIMEBASE values for the CPU). This first BASIC example makes SAM sound more feminine: SYS 60946,3,32 This second example makes SAM sound like a giant: SYS 60946,3,110 Both examples assume that BANK 1 is active.
The SPEED value should be less than about 160 to prevent distorted audio (actual maximum depends on phonemes used and their stress level). Because the longest duration for a single phoneme part is 16, using values for SPEED of 16 or less means the individual phoneme's time period will be the main factor controlling speed (in other words, the global SPEED doesn't really control SAM's general speed). As a practical matter (with recommended TIMEBASE for your CPU speed), values less than about 32 will generate speech so fast it will be (nearly) indecipherable. This first BASIC example makes SAM speak quickly: SYS 60946,4,40 This second example makes SAM speak slowly: SYS 60946,4,120 Both examples assume that BANK 1 is active.
The default TIMEBASE is 2 so as to be compatible with the C64 version. Here are the recommended settings for normal sound (see also CPUFIX):
Note the recommended SLOW PAL value of 1 is if you want that frequency calculation to work. However, the C64 version has no PAL correction, so PAL users familiar C64 SAM might prefer the default value of 2. Now that I think about it, experienced C64 PAL users might want to make NTSC SAM sound like PAL! In that case, try using a value of 3 for SLOW CPU speed. Note that because of the SuperCPU, values greater than 255 may be needed. So the value must be split into a low-byte and high-byte. For example, to use 2MHz (FAST) CPU speed on an NTSC machine, change the TIMEBASE to 30, like this: SYS 60946,5, 30, 0 Another example, to use 20MHz (SuperCPU) speed on an NTSC machine, change the TIMEBASE to 582, like this: SYS 60946,5, 582 AND 255, 582/256 The same example again, but in ML: LDA #5 ;poke 'Address' 5 (TIMEBASE) LDX #<582 ;value low LDY #>582 ;value high JSR $EE12 ;call Poker directly (only if running in BANK 1 -- otherwise use FAR_CALL) All three examples assume that BANK 1 is active. Note: TIMEBASE does not affect the pitch and speed of a few (parts of) 'noisy' phonemes. So if you are adjusting for a change in CPU speed, the NOISES also need to be changed (or simply call CPUFIX).
Find out more about SAM+Reciter (C64) on Wikipedia! SAM (64) © Don't Ask, Inc., 1982 SAM 128 © H2Obsession, 2015 Webpage © H2Obsession, 2015, 2016, 2018 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||