--- title: "Streams and Channels" type: "article" slug: "streams-and-channels" url: "http://localhost/article/streams-and-channels/" markdown_url: "http://localhost/article/streams-and-channels.md" published_at: "2022-10-07T12:26:20+00:00" modified_at: "2026-08-02T09:50:47+00:00" featured_image: url: "http://localhost/wp-content/uploads/2022/04/20230809-041332.jpg" excerpt: "A stream is a dataflow in/out the program. Its home terminal is the program; its remote terminal is deliberately assigned to a channel. A channel is a ML program accessed by the BASIC program via streams. IT IS NOT AN EXTERNAL APPARATUS, like a modem or robot!! The ML program could govern an outside device…" category: - name: "LISTing Newsletter" slug: "listing-newsletter" taxonomy: "category" url: "http://localhost/category/periodicals/listing-newsletter/" post_tag: - name: "Best of Timex/Sinclair 2068 Articles and Documents" slug: "ts2068best" taxonomy: "post_tag" url: "http://localhost/tag/ts2068best/" - name: "Reference" slug: "reference" taxonomy: "post_tag" url: "http://localhost/tag/reference/" - name: "TS 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" indiv: - name: "John Pazmino" slug: "john-pazmino" taxonomy: "indiv" url: "http://localhost/indiv/john-pazmino/" publication_r: id: 38992 title: "LISTing Newsletter" type: "periodical" url: "http://localhost/periodical/listing-newsletter/" authors: "John Pazmino" authors_r: - name: "John Pazmino" slug: "john-pazmino" taxonomy: "indiv" url: "http://localhost/indiv/john-pazmino/" issues_articles: - id: 40207 title: "LISTing Newsletter October 1986" type: "issue" url: "http://localhost/issue/listing-newsletter-october-1986/" pages: "3-4" pubdate: "October 1986" archive_link: false gallery: - url: "http://localhost/wp-content/uploads/2022/10/streaming.png" - url: "http://localhost/wp-content/uploads/2022/10/streaming-1.png" --- # Streams and Channels A stream is a dataflow in/out the program. Its home terminal is the program; its remote terminal is deliberately assigned to a channel. A channel is a ML program accessed by the BASIC program via streams. IT IS NOT AN EXTERNAL APPARATUS, like a modem or robot!! The ML program could govern an outside device but it plain doesn’t have to. A stream can terminate in only one channel at a time; a channel may be the terminus of many streams. A stream is a two-way “road” connecting the BASIC and ML programs and can handle traffic into or out of the BASIC program. Data is sent out of the program with (typically) the PRINT#n. n is the number of the stream. Input to the program is fielded (typically) by INPUT#n. The TS instrument has 19 streams and indefinitely many channels. Streams are numbered −3 to 15. #−3 to #−1 are phantom streams reserved for TS internal use. Channels are designated by a character, usually a letter. The TS preassigns streams #0 to #3 to channels “K”, “S”, and “P” in hoc schema: - #0 & #1 — “K”, keyboard & lower screen - #2 — “S”, upper screen - #3 — “P”, TS printer The printer is specifically the TS proprietary unit (or workalike), like the Alphacon 32, Floyd 40, or TS 2040. IT IS NOT A GENERIC PRINTER AT ALL. The TS preallocates stream #2 to PRINT, LIST; #3 to LPRINT, LLIST; #0/1 to INPUT, INKEY$. You don’t have to specify these streams. To redirect flow you give the stream. PRINT#3 sends output to the printer. Some combinations don’t work. INPUT#2 looks for data coming from the television screen. ‘Cuz there isn’t any, an error is triggered. These stream-channel assignments are cemented; you can’t change them. You cannot, for instance, assign stream #0 to channel “P”; it just won’t take. NOTATE MAGIS BENE!: These channels ARE NOT APPARATUS ATTACHED TO THE COMPUTER. They are ML codes (in the ROM). That these codes operate the TV, etc., is immaterial. The streams are assigned to ML programs. You can use the remaining streams, #4 thru #15, to control your own machine language programs. To do so, you must do some simple poking into the STRMS zone of RAM and write a channel record in RAM. First write (or load) the ML program; note the entry addresses for the program’s input and output. If one is absent there better be an entry for error trapping, or you’ll use the ROM error routine. Write a five-byte record for this ML program. It’s best to tack it in front or back of the program, but note its start address. The first two bytes are the lo-hi address of the output entry point. The 2nd two are the lo-hi address of the input entry point. Where one is absent, put in the entry address of the error routine. The 5th is the code of the character designation for this channel. It can not be “K”, “P”, “R”, or “S” ‘cuz these already are given to the onboard channels. (“R” is RAMspace and is assigned to phantom stream #−1.) Use a letter rather than a number, symbol, or token. Pick a vacant stream number. Then calculate (stream address) = (23574) + (2) × (stream number), and (channel offset) = (channel address) − (26687) Do POKE (stream address), (channel offset)lo and POKE (stream address+1), (channel offset)hi. Now the new stream is created and opened to the new channel. To operate your ML program, use INPUT#n, PRINT#n, etc., n being the number for the new stream. To close the stream, poke zeros into that stream’s address & address+1. In operation, INPUT#n goes to the STRMS region, looks up stream #n, picks up the channel offset, regenerates the channel address, goes to the channel record, picks up the input address, goes to the input address, processes the ML code starting at this point, returns to the BASIC program. Understand most well that the BASIC program regards INPUT#n, LIST#n, etc as orthodox INPUT, LIST etc with no fettering to a this or that stream. Hence PRINT#n, say, will be structured just like a primitive PRINT, with attributes, control chars, punctuations, the one and all. Your ML program must deal with this stream of bytes – even if it just passes them up. Likewise, INPUT#n will be received by the BASIC exactly as if the chars were keystruck by a vivid body, with keywords, capslock, graphiclock, el todo y uno. Your BASIC program must cope with this char stream in whatsoever appropriate manner. Just as the ML program itself must be protected against corruption during machine operation, as by its placement above RAMTOP, so, too, must be defended the very channel records. Lo here an example, the Zebratalker voicebox. The driving program, ZTALKER, is stored from 59000 on up. The entry for the output section is at 59200; error section, 59203. There’s no “input” from the voicebox, the code starting at 59203 traps attempts to do INPUT on the Zebratalker. The zone starting at 59206 does the various figuring and pokes to establish the new stream and channel when you do RANDOMISE USR 59206. The channel is designated “Z” (God only knows why) and the stream is #4. ZTALKER puts the new channel record above the existing ones, which is fine – if you’re careful. It is all the way best to put your own channel records in a free area of protected RAM. Regardez-vous en suite: The article illustrates the ZTALKER entry stubs and the channel file with hand-drawn box diagrams, reproduced here as byte listings: ``` 59000 8 start of ZTALKER code 59200 195, 151, 231 entry for output — JP 59287 59203 195, 149, 231 entry for error trap — JP 59285 59206 195, 77, 231 initialization of streams & channels ``` ``` 26703 0, 5, 191, 17, 80 existing channel "P" 26708 64, 231, 67, 231, 90 new channel "Z" ``` ZTALKER, when entered by the BASIC program’s output (that is, a PRINT#4 statement) does a JP 59287 to some interior region of itself to actually convert the text of PRINT#4 into speech. If an attempt by BASIC to receive input is made, as by an INKEY$#4, ZTALKER does a JP 59285 to intercept the attempt. The channel record is installed, by the code at 59206 on up, at 26708. The first two bytes are 64; 231, the lo-hi equivalent of address 59200. The next two are 67; 231, for 59203. The last byte is 90, the charcode for “Z”. You can assign any code to designate the channel, but don’t use “K”, “P”, “R”, or “S”, since these are already assigned to the built-in channels. Now go to the address for stream #4, which is 23574 + 2 × 4, or 23582. The channel offset is 26708 − 26687, or 21. ``` 23580 16, 0 existing stream #3 23582 21, 0 new stream #4 ``` Poke 21 into addresses 23582–23583. The lo byte is 21; hi, 0. And, miraculo miraculorum, stream #4 is opened for channel “Z”. That may be, you can do `PRINT#4;a$` in BASIC and a$ will be placed into ZTALKER and be turned into (passable) speech. You just operated an ML program directly from BASIC. To consider an other example, look at stream #3 and channel “P”. These are two of the cemented stream-channel links in the TS. The offset read out from the stream file is 16 + 256 × 0, or 16. 16 + 26687 is 26703, the start of the channel record. The output address is 0 + 256 × 5, or 1280; input address is 191 + 256 × 17, or 4543. The designation is 80, for “P”. Recourse to your ROM atlas. Address 1280 is the entry to the omnibus print-out routine – channel “P” is the “printer” channel. Address 4543 is not a regular input but an errortrap. It triggers a “J – invalid I/O device” message. You cannot get input from the TS printer.