+FarmerPotato Posted May 5, 2018 Share Posted May 5, 2018 (edited) May 4th Musical offering: FORTI Decompiled 1. Introduction FORTI was a sound card for the TI-99/4A PEB, with software written in FORTH. It featured 4 of the TI sound chips, giving 12 programmable voices. Each chip's tone#3 generator was paired with a noise generator, for bass or percussion. The FORTI software was best known in the form of its 3-voice demo of Bach's FWV 578 "Little" Fugue in G Minor (G-Moll), distributed with the TI FORTH Demo disk in 1983-84. The Bach demo used only 3 voices, on the sound chip in the 4A. However, other compositions were made for 12 voices. I know of Chariots of Fire (Vangelis), Ricercar a 6 (Bach, Musical Offering, aka Prussian Fugue), and a newer Bach "Litle" Fugue (first 1K lost). On the plain 4A, these sound terrible but tantalizing, as 11 voices compete skilfully but hopelessly for 3 hardware sound channels. What I did Starting from a compiled FORTI demo of Chariots of Fire, I decompiled the FORTH words, read out data structures, and disassembled the code for the MUSIC word, which is in the ISR sound driver. I benefitted from a small amount of leftover original source (from the corrupted Bach demo) and the FORTI user manual, but most of FORTI, especially the music compiling words, is lost to me and has to be reverse engineered. From internal evidence, the Bach demo is older than Chariots of Fire. The FORTI user manual indicates features not supported in the Chariots of Fire MUSIC driver, which I may create again. I classify features into three versions of the FORTI software: B. Bach Demo (TI FORTH graphics demo) C. Chariots of Fire D. Distribution with FORTI manual Unless stated otherwise, I discuss features found in Chariots of Fire. 2. Capabilities of FORTI: 2.1 The Data Structures Voiceline - a list of note numbers (byte) and duration in ticks (byte). Envelope - a list of attenuation bytes, with looping index (high bit set). Workspace - set of 16 TMS9900 workspace registers holding the context for one sound channel. Pitchtable - arrays of frequency cmds for each note number. 2.2 The capabilities of the MUSIC ISR routine For each of 12 voices, there is a separate voiceline, envelope, and pitchtable, assigned to a hardware sound channel. The differential tempo counter: Note durations in ticks (1/60th second) are multiplied by 32 and added into a "Next Note" countdown timer (per voice). On each interrupt tick (1/60th second), the value DEL is subtracted from the countdown timer. DEL has an initial value of 32. When DEL is modified by the RIT, ACC, and TEMPO words, the effect is that the tempo is increased or decreased. The duration timer is never cleared so no time is lost. All voices move ahead at the same tempo. When the duration timer reaches 0 or less (it is initialized to 0 to start music) a new note and duration are taken from the voiceline. If the duration is 0, the channel is silenced, and the ISR returns -1 on the stack (bug: and the ISR is removed?) Looping inside the envelope: in terms of an ADSR model, the envelope will begin with an Attack-Decay section, a Sustain (looped) section, and an optional Release (tail) section which can apply during the last portion of each note. The Release feature is used in the Bach Demo but not Chariots of Fire (buggy). Envelope bytes are processed every tick (1/60th second), not modified by tempo. The 16 attenuation values are remapped through a dynamic offset DYN and a 48-byte dynamics table (DYT). This allows words like +VOLUME and -VOLUME to take effect 2.3 Pitchtables A pitchtable entry is 2 data bytes to send to the sound chip for a note number (the channel number will be added later). Note number 0 is used as a rest, but a rest is actually defined by having 0 for the sound chip period. PT0 is the regular pitchtable. Note number 37 corresponds to low A or 110 Hz, which is the lowest musical note a tone generator can produce. Because of this limitation, PT0 fills the bottom 3 octaves (notes 1-36) with a copy of the octave 37-48. If a voice using PT0 plays notes in the range 1-36, they will still be heard, but in a higher octave. PT1 notes load white noise for percussion. PT4 is for channel 3 to drive the periodic noise channel and begins with note 0 corresponding to 13.75 Hz. 3. Examples: Voiceline: 0 VARIABLE VOICE1 QU C D E F EI G A B C 0 , compiles a list of note-duration pairs into VOICE1 relying on definitions such as these: 49 VARIABLE XPOSE : &* XPOSE @ + SWPB DURATION C@ + , ; : A 0 &* ; : A# 1 &* ; : C 3 &* ; : AA 12 &* ; : CC 15 &* ; : EI 24 DURATION C! ; : QU 48 DURATION C! ; : RE DURATION C@ , ; : OCTAVE 12 * 49 + XPOSE ! ; ( n -- ) The FORTI manual says to compile a voiceline like so: START VOICE: VOICE1 ( 1 ) QU C D E F ( 2 ) QU G A B C FINIS My example based on C/ uses a lower level way: ( Verdi Requiem Mv2 trumpet ) 0 OCTAVE 0 VARIABLE VOICE2 ( 131 ) 3E RE C E G E G RE C E G E G ( 132 ) Q CC RE RE 3E C E$ A$ ( 133 ) Q CC H RE 3E C E$ G ( 134 ) Q C RE H RE 0 , 4. Internals 4.1 Workspace registers FORTI takes advantage of the TMS9900 workspace pointer context. There is a block of 12 workspaces allocated in the dictionary, one for each voice. In MUSIC version C with dancing sprites, they must be contiguous so that a sprite table address can be found from (STWP-WS1)/8. In version B they are not contiguous. In the Bach demo, (no sprites) Workspace WS1 might be set up like this: VOICE2 VARIABLE WS1 PT0 , TRUMPET1 , 0 , 0 , 8000 , 9000 , 12 ALLOT But with dancing sprites, all WS must be contiguous, in order to calculate the sprite#. 0 VARIABLE WS1 17E ALLOT WS1 20 + WS2 CONSTANT WS1 40 + WS3 CONSTANT WS1 60 + WS4 CONSTANT WS1 80 + WS5 CONSTANT WS1 A0 + WS6 CONSTANT WS1 C0 + WS7 CONSTANT WS1 E0 + WS8 CONSTANT WS1 100 + WS9 CONSTANT WS1 120 + WSA CONSTANT WS1 140 + WSB CONSTANT WS1 160 + WSC CONSTANT The word MUSIC is the core of the ISR and is written in assembler. The first instructions of MUSIC pulls the WP off the stack; ED10 0201 LI R1,>ED18 ED12 ED18 ED14 C019 MOV *SP,R0 fetch WSP ( wsp -- f ) ED16 0400 BLWP R0 effect is R0->WP R1->PC. no LWP on 9900 The full code is in Listing 1 at the end of this article. The workspace registers are initialized before MUSIC first runs, and have the following meaning: FORTI WS usage. WS is a register workspace ------------------------ R0 voice or cascade addr. List of byte pairs (note#,dur) R1 pitch-table: e.g. PT0 or PT1 R2 envelope. e.g. PLUCK3 or ORGAN2 R3 index into envelope R4 countdown timer to next note. init to 0 to begin. R5 const pitch cmd byte R6 const attn cmd byte (for a noise, pitch is tone#3 and attn is tone#4/noise) R7 pitch cmd word for current note or 0 for rest R8 temp. compute vdp address (for sprite) or envelope address R9 vdp addr of sppat# R10 copy of SGCA, sound card address (copied from SGCA at each ISR entry, sic) R11 not used R12 temp. compute vdp data byte (for sprite) R13 ... R15 after blwp, not used ( Register numbers for use in assembling MUSIC - EO ) 0 CONSTANT NTP ( Note table / voice pointer ) 1 CONSTANT PTS ( pitch table start ) 2 CONSTANT ATS ( attenuation table start / envelope ) 3 CONSTANT ATP ( attenuation table offset ) 4 CONSTANT DUR ( countdown timer duration ) 5 CONSTANT PVID ( pitch voice ID ) 6 CONSTANT VVID ( volume voice ID ) A CONSTANT SG ( sound card address ) C CONSTANT PNDX ( pattern number vdp address ) ( D E F are clobbered on entry to MUSIC but could be temps ) 4.2 Player wordsWords PLA1, PLA3, PLA12 begin playing 1, 3, or 12 voices, resp. : PLA12 ' BMUSIC XMUS ; ( play : PLA3 ' CMUSIC XMUS ; ( play only WS1-3 on internal snd only ) : PLA1 ' DMUSIC XMUS ; ( play only WS1 on internal snd only ) where : MUSIC0 85EE SGCA ! MUSIC ; ( 1110 1110 only chip #0 with enable low ) : MUSIC1 85F6 SGCA ! MUSIC ; ( 1111 0110 only chip #1 ) : MUSIC2 85FA SGCA ! MUSIC ; ( 1111 1010 only chip #2 ) : MUSIC3 85FC SGCA ! MUSIC ; ( 1111 1100 only chip #3 ) : MUSIC4 84FE SGCA ! MUSIC ; ( 1111 1110 internal only ) : MUSIC5 857E SGCA ! MUSIC ; ( 0111 1110 say chip 4 ) : MUSIC6 85BE SGCA ! MUSIC ; ( 1011 1110 say chip 5 ) : MUSIC7 85DE SGCA ! MUSIC ; ( 1101 1110 say chip 6 ) 3424 VARIABLE PSTART : XMUSIC WS1 MUSIC0 OR IF 83C4 @ PSTART ! 0 83C4 ! OFF ENDIF ; : DMUSIC 0 XMUSIC ; : YMUSIC WS2 MUSIC0 WS3 MUSIC0 OR OR XMUSIC ; : BMUSIC WS4 MUSIC1 WS5 MUSIC1 WS6 MUSIC1 WS7 MUSIC2 WS8 MUSIC2 WSA MUSIC3 WSB MUSIC3 WSC MUSIC3 OR OR OR OR OR OR OR YMUSIC ; : CMUSIC 0 YMUSIC ; ( for PLA3 ) : XMUS CFA ISR ! INTLNK @ PSTART ! ; When playing just one voice: : MUSIC0 85EE SGCA ! MUSIC ; ( 1110 1110 only chip #1 with enable low ) : XMUSIC WS1 MUSIC0 OR IF 83C4 @ PSTART ! 0 83C4 ! OFF ENDIF ; ( f/finished? -- ) : DMUSIC 0 XMUSIC ; : PLA1 ' DMUSIC XMUS ; ( play only WS1 on chip#1 or internal snd ) In PLA1, DMUSIC is the ISR which calls MUSIC on one workspace pointer. (PLA12 and BMUSIC make a player that calls each of 12 voices.) 4.3 Sprites The version of MUSIC in Chariots of Fire draws dancing sprites on the screen (Bach demo does not have this.) For each of 12 voices, there is a sprite. The note number translates to a column on the screen, while the attenuation is shown by a colored bar where height indicates loudness. 4.4 Misc Chariots of Fire utilizes 11 sound channels across 4 chips. Interestingly, it defines addresses for MUSIC5,6,7 as if the author imagined having more chips than 4. 5. Optimizations It's quite likely that I'm not analyzing the final version of the MUSIC word. That said, I see the following optimizations that could be made: * SGCA is placed on the stack and copied to the workspace R10 on each tick. This should be configured before music starts playing, just like other registers that don't change. * The envelope release (or tail) segment looks buggy in Chariots of Fire (whose envelopes don't rely on it.) * Byte swapping and SRL by 8. movb *r8,r8 ab @DYN+1,r8 srl r8,8 movb @DYT(r8),r8 movb r8,*r10 could be clr r11 movb *r8,r11 swpb r11 a @DYN,r11 movb @DYT(r11),*r10 6. Missing Words Parts of the music entry system were not present in the compiled demo: Defining words like VOICE: FINIS and <ENV: ENV> were not recovered. I speculate that the demos B and C were created in a lower level way, and that these defining words were invented for the final distributon. Envelope word =REPEAT to encode the sustain loop 3 SHARPS established a key signature, modifying the behavior of note words like F. In the demo, F pushes a constant note number 8 (plus octave). This implies T for Tie or slur is not present. I don't see that MUSIC implements any means to vary frequency. R: and :R to repeat a section in a voiceline. These save memory, but would require runtime implementation in MUSIC. convenience word =TEMPO counting words =MEAS and +MEAS Envelope defining words <ENV: ENV> produce code that copies the envelope PFA into a WS. This requires a <BUILDS DOES> construct. In the demo, envelope words are just arrays. The words +VOLUME and -VOLUME and dynamic markings from PPP to FFF. CONDUCTOR is the top defining word and is not present SILENT is not present +FIFTH and words that transpose voices at runtime, not compile time, will require support in MUSIC. <ALBUM and ALBUM> words =GR and GR that subtracts time (for a grace note) from the previous note duration. In the demo, GR sets DURATION to 1 tick. =FERMATA and FERMATA =DRUM to set a WS to play noise <PHRASE: PHRASE> 7. Future Innovations I was disappointed to find nothing about tremolo in this demo. Envelopes are just attenuation changes, which is how an organ tremolo operates, but on other instruments, tremolo means to vary the frequency, or play two frequencies for the overtones. (T or Tie/Slur effect on frequency is unknown; perhaps it just skips the tail.) An envelope for pitch would allow many more effects. The FORTI manual lacks a dictionary. The pitch table is flexible enough to allow different temperament. The pitch table we take for granted is the equal tempered system in which music can be transposed to another key without changing its character. 8. Acknowledgments David Olson retrieved the Chariots of Fire demo disk. Rene LeBlanc for his FORTH disassembler, which I obtained in 1985 and never used until now. Gene Hitz and Owen Brand provided the MATIUG disk library, which I converted to DSK format, finding the TI FORTH source. The BERG/WERNECKE FORTH decompiler found in the MATIUG disk library. Lee Stewart's fbFORTH and TI FORTH manuals which I used as a reference throughout, especially on the dictionary entry structure. Tursi for Classic99 in which I did most of the work. Kryoflux hardware and software was used to efficiently acquire hundreds of legacy disks. CANTRELL, the TI engineer named on the FORTI "stereo card" schematic. Who is CANTRELL? 9. References FORTI Music Card Users Manual and Schematic at WHTech ADSR definition Listing 1 * code field of MUSIC * Load workspace from stack arg ED10 0201 LI R1,>ED18 ED12 ED18 ED14 C019 mov *SP,R0 fetch WSP ( wsp -- f ) ED16 0400 blwp R0 effect is R0->WP R1->PC. no LWP on 9900 ED18 C2A0 mov @SGCA,R10 ECCE is pfa of variable SGCA. typ 85EE(#1 chip) ECCE ED1C 04CC clr R12 ED1E C104 mov R4,R4 duration timer. clear to start ED20 1531 jgt LABEL2 * next note ED22 D330 movb *R0+,R12 get note number in R12 ED24 098C srl R12,8 ED26 C1CC mov R12,R7 get note number in R7 ED28 0A9C sla R12,9 sprite col = note# * 2 ED2A 0209 li R9,>d844 WS1 D844 ED2E 02A8 stwp R8 ED30 6209 s R9,R8 (WSx - WS1) is a multiple of 32 ED32 0938 srl R8,3 divide by 8 ED34 0228 ai R8,>4301 address to write, in SAT 4301 ED38 06C8 swpb R8 ED3A D808 movb R8,@>8c02 set up VDP address 8C02 ED3E 06C8 swpb R8 ED40 D808 movb R8,@>8c02 8C02 ED44 D80C movb R12,@>8c00 sprite col = note# * 2 8C00 ED48 0588 inc R8 ED4A C248 mov R8,R9 vdp addr of sppat# ED4C D230 movb *R0+,R8 duration ED4E 0988 srl R8,8 ED50 0A58 sla R8,5 times 32 . 32 is the neutral value of DEL ED52 A108 a R8,R4 add, because need to pay time debt ED54 1509 jgt LABEL1 * silence * bug: if R4 is at worst 1-DEL, R8 is at worst 32, if R8<DEL-1 then music may stall FINIS ED56 0640 dect R0 leave R0 pointing to the last (valid) note ED58 C206 mov R6,R8 attn cmd byte ED5A 0228 ai R8,>0f00 silence 0F00 ED5E D688 movb R8,*R10 write to sound chip ED60 02E0 lwpi >8300 8300 ED64 0719 seto *SP put -1 on the stack ( wsp -- f ) ED66 045F b *NEXT LABEL1 ED68 A1C7 a R7,R7 note# * 2 ED6A A1C1 a R1,R7 pitch table address ED6C C1D7 mov *R7,R7 ED6E 1605 jne NOTE else, turn off voice: REST ED70 C206 mov R6,R8 attn cmd byte ED72 0228 ai R8,>0f00 silence 0F00 ED76 D688 movb R8,*R10 write to sound chip ED78 1005 jmp LABEL2 why not LABEL6 NOTE ED7A A1C5 a R5,R7 pitch cmd byte ED7C D687 movb R7,*R10 write to sound chip ED7E 06C7 swpb R7 ED80 D687 movb R7,*R10 write to sound chip ED82 04C3 clr R3 * note in progress LABEL2 ED84 C1C7 mov R7,R7 pitch cmd or 0 if none ED86 132E jeq LABEL6 nothing to do ED88 D212 movb *R2,R8 envelope first byte (N in sustain) ED8A 0938 srl R8,3 ED8C 8108 c R8,R4 R4 is counting down from duration*32 ED8E 1501 jgt SSTAIN ED90 1003 jmp LABEL3 SSTAIN ED92 0203 li R3,>003f start envelope at 3fh-R8*32 003F ED96 60C8 s R8,R3 LABEL3 ED98 0283 ci R3,>003f 003F ED9C 1102 jlt LABEL4 ED9E 0203 li R3,>003f R3 max 3F 003F LABEL4 EDA2 0583 inc R3 at least 1 EDA4 C203 mov R3,R8 EDA6 A202 a R2,R8 envelope pointer in R8 EDA8 D218 movb *R8,R8 EDAA 0988 srl R8,8 EDAC 0288 ci R8,>0080 0-F attentuation, 8x cmd byte 0080 EDB0 1501 jgt ENVJMP EDB2 1006 jmp LABEL5 * envelope cmd byte ENVJMP EDB4 0228 ai R8,->80 FF80 EDB8 C0C8 mov R8,R3 new envelope index in R3 EDBA A202 a R2,R8 EDBC D218 movb *R8,R8 they seem to have run out of registers EDBE 1001 jmp LABEL6 * R8 lsb is attn LABEL5 EDC0 06C8 swpb R8 * adjust attn by dynamics table LABEL6 EDC2 B220 ab @DYN+1,R8 ECD9 EDC6 0988 srl R8,8 ugh EDC8 D228 movb @DYT(R8),R8 D1BA EDCC 06C9 swpb R9 vdp address of sppat# EDCE D809 movb R9,@>8c02 8C02 EDD2 06C9 swpb R9 EDD4 D809 movb R9,@>8c02 8C02 EDD8 0A28 sla R8,2 mpy by 4 EDDA D808 movb R8,@>8c00 set sppat# to attn 8C00 EDDE 0928 srl R8,2 EDE0 A206 a R6,R8 add attn cmd byte EDE2 D688 movb R8,*R10 write to sound chip LABEL6 EDE4 6120 s @DEL,R4 Subtract DEL from timer CC60 EDE8 02E0 lwpi >8300 8300 EDEC 04D9 clr *SP put 0 on the stack EDEE 045F b *NEXT Edited May 5, 2018 by FarmerPotato 9 Quote Link to comment Share on other sites More sharing options...
+FarmerPotato Posted May 5, 2018 Author Share Posted May 5, 2018 Download the binaries here: Bach Demo for "Little" Fugue in G Minor 6 LOAD BPLAY Chariots of Fire for Chariots of Fire: 59 BLOAD PLAY or for Ricercar a 6 49 BLOAD PLAY 2 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted May 5, 2018 Share Posted May 5, 2018 Wow! That is an impressive amount of work. Any plans to make a run of ForTI cards? Maybe with @Ksarul? ...lee 3 Quote Link to comment Share on other sites More sharing options...
+Ksarul Posted May 5, 2018 Share Posted May 5, 2018 A PEB FORTI card is on my list, but it is a bit lower down (five or six right now). 2 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted May 5, 2018 Share Posted May 5, 2018 Download the binaries here: Bach Demo for "Little" Fugue in G Minor 6 LOAD BPLAY Chariots of Fire for Chariots of Fire: 59 BLOAD PLAY or for Ricercar a 6 49 BLOAD PLAY This really cool. I have the beginnings of this kind of music language for Camel Forth but this is fully developed. It inspires me to continue development in this direction. Reading through the manual I get lots of ideas. I am curious about the notation's use of flats. I saw that they use A$ B$ etc for flats if I read it correctly. To me the obvious labels are Ab Bb Cb A# B# D# etc. I suspect it has something to do with the search mechanism being case insensitive so their Forth could not differentiate between BB and Bb but's that's just a guess. Thanks for this excellent reverse engineering work. B 1 Quote Link to comment Share on other sites More sharing options...
+FarmerPotato Posted May 14, 2018 Author Share Posted May 14, 2018 Thank you for the comments. I am continuing to work on this. I will have a source code update next weekend. In the absence of a copy of the actual FORTI distribution disk (D), here is my plan: Road Map for FORTI Clean source (compilable) for (B) Bach Demo and © Chariots of Fire, Ricercar a 8. Including some defining word features implemented to match (D) FORTH assembler version of MUSIC, as well as CODE version (machine code) Full implementation of features of (D) from user manual, with some innovations. Collection of Bach inventions and sinfonias for 2-3 voices MIDI import tool TRON arcade game music (originally used AY-8910) Well-known TI game songs remixed Tool to export compiled music as A/L source for use outside FORTH Reference release (E) (Erik) with innovations 4-chip FORTI card PCB (not made yet) Extra special music card project compatible with FORTI (hardware built! waiting while I do software) Major musical work demo MIDI player Speech synthesizer integration Animatronic art installation 4 Quote Link to comment Share on other sites More sharing options...
+acadiel Posted May 15, 2018 Share Posted May 15, 2018 Amazing. I had a bare FORTI board a while back that I gave to someone who was going to build it. Been so long, I forgot who, but hopefully they read this thread Sent from my moto x4 using Tapatalk Quote Link to comment Share on other sites More sharing options...
Asmusr Posted September 24 Share Posted September 24 On 5/5/2018 at 4:34 AM, FarmerPotato said: Download the binaries here: Bach Demo for "Little" Fugue in G Minor 6 LOAD BPLAY Chariots of Fire for Chariots of Fire: 59 BLOAD PLAY or for Ricercar a 6 49 BLOAD PLAY Are those files still available? 1 Quote Link to comment Share on other sites More sharing options...
+FarmerPotato Posted September 25 Author Share Posted September 25 3 hours ago, Asmusr said: Are those files still available? Yes, the top directory is good: https://github.com/olsone/forti Quote Link to comment Share on other sites More sharing options...
+chue Posted September 25 Share Posted September 25 1 hour ago, FarmerPotato said: Yes, the top directory is good: https://github.com/olsone/forti I am getting a page not found when I click on the link. Is the repo public? Quote Link to comment Share on other sites More sharing options...
+FarmerPotato Posted September 25 Author Share Posted September 25 7 minutes ago, chue said: I am getting a page not found when I click on the link. Is the repo public? Oops. Now public. 2 1 Quote Link to comment Share on other sites More sharing options...
Asmusr Posted September 25 Share Posted September 25 2 hours ago, FarmerPotato said: Oops. Now public. Thanks. Could you explain how to run these demos to a Forth noob? Can you run them in fbForth? Quote Link to comment Share on other sites More sharing options...
Asmusr Posted September 25 Share Posted September 25 10 hours ago, Asmusr said: Thanks. Could you explain how to run these demos to a Forth noob? Can you run them in fbForth? I think I understand now: You need to run FORTH as E/A#3, and then it's using sector I/O. Quote Link to comment Share on other sites More sharing options...
+FarmerPotato Posted September 25 Author Share Posted September 25 2 hours ago, Asmusr said: I think I understand now: You need to run FORTH as E/A#3, and then it's using sector I/O. Yeah, these are the DSK images. Easy to use in Classic99 with E/A. There is no source code. (I decompiled some.) I was hoping for source code on the original disk from @dhe but no. At least I can decompile what was in the distribution to users. FORTI2 A long while ago, I re-implemented a chunk of what the FORTi user manual describes. Long since I tested it on TI Forth. I want to compile it in fbForth. I didn't implement the CONDUCTOR or ALBUM words. I did complete VOICE: and ENV: defining words. With all the notes and durations. I changed the offset to use MIDI numbers. Also PLAYER, FIFTH, BASS etc to set up before starting MUSIC. So it does a lot, but there is no CONDUCTOR involved to change TEMPO or dynamics. Another way is I could add tempo and dynamics in the VOICE: But TEMPO only makes sense if it's one PLAYER. (Especially parallel CRESC will not have the intended effect.) On the other hand, if you have dynamics in a CONDUCTOR sequence it's better for editing (that is, conducting!) Suppose you want to assign the same VOICE to separate players with different dynamics. Oh, another feature during VOICE: compiling: I put in a MEAS; word for you to indicate end of measure. In MEAS; if the durations don't add up to a multiple of the time signature, the compiler gives a warning "Short measure at 12, adding rest" Other possibilities might be n +MEAS or n MEAS! The need is for a long period of inactivity in one voice. The other way to do that is to break the voice into pieces and write the CONDUCTOR to launch them. The CONDUCTOR also might compile the +MEAS word to signal its inactivity. In FORTi you have to write a string of WH RE RE RE RE... which would be error-prone. If you are typing in music from a score, you know the measure numbers, and MEAS is handy. You can always add your own compiling words, but my changes depend on adding to the duration for every note compiled. Oh, another idea I did in ANS Forth: ( n ) NOTE is the compiling word called by A etc, but it is DEFER. DEFER NOTE ' PLAY-NOW IS NOTE ' COMPILE-NOTE IS NOTE Another way might be to make NOTE compile or play immediately depending on STATE being compile. It's really a great flexible system that Lee Caldwell built so long ago. 3 Quote Link to comment Share on other sites More sharing options...
Asmusr Posted September 26 Share Posted September 26 I added the FORTi sound card to JS99'er and fixed the sector IO, so now the demos work. 3 3 Quote Link to comment Share on other sites More sharing options...
Asmusr Posted September 26 Share Posted September 26 11 hours ago, FarmerPotato said: Yeah, these are the DSK images. Easy to use in Classic99 with E/A. But I don't think Classic99 emulates the FORTi, at least it didn't sound like it. I also looked at the MAME implementation, and it appears that it has the enable bits for the PSGs reversed. A PSG should be on when the bit is off, AFAIK. void forti_device::write(offs_t offset, uint8_t data) { // Decode for 8400-87ff if ((offset & 0xfc01) == 0x8400) { // The generators can be accessed in parallel if ((offset & 0x2)!=0) m_generator1->write(data); if ((offset & 0x4)!=0) m_generator2->write(data); if ((offset & 0x8)!=0) m_generator3->write(data); if ((offset & 0x10)!=0) m_generator4->write(data); } } Quote Link to comment Share on other sites More sharing options...
+FarmerPotato Posted September 26 Author Share Posted September 26 Index of the FORTi Distribution disk (or 'D'). Disk image provided by @dhe. Thanks Dan! I see that Lee Caldwell preferred to have DSK2 begin at screen 100, not 90: DECIMAL 100 DISK_SIZE ! 300 DISK_HI ! ( Screens 90-99 would be an unused second side. ) A screen or block is 4 sectors or 1024 bytes. "Offset" is a hexadecimal address into the 90K disk image file. Hexadecimal numbers start with ">". Screen 1 is at offset >400 Screen 4 is at offset >1000 Screen 20 (decimal) >5000 Compiled FORTi is brought in by 20 BLOAD . The first 24 bytes of a BSAVE/BLOAD block is for the loader, then 1000 bytes of data. 40 LOAD is the ALBUM which utilizes up to screen 82. I see screen numbers to BLOAD under ( TABLES ) There are 6 songs in ALBUM. <ALBUM 46 51 52 56 78 58 ALBUM> 46 Adeste Fideles 51 Scale test 52 Sailor's Hornpipe image offset d000. 56 Frere Jacques image offset e000. 58 Boogie image offset e800. 78 Ermuntre Dich image offset 13800. Load Address Kind Scr Offset First Last Comment ------ --- ----- ---- ---- ----------------------- source 3 Boot screen message 4-5 Custom to FORTi help 6 1800 Editor Keys help 7 1a00 Instructions to load FORTi music 8 2000 empty? mostly formatted E5 8 1/2 2200 FORTH object BSAVE 20 5000 bc8a e288 TI Forth: .BLK CONSTANT VARIABLE ... BSAVE 21-28 e288 TI Forth BSAVE 29 7400 dfb2 e288 TI Forth: SQNTL RLTV ... BSAVE 30-37 7800 c4cc e13a FORTi music defining words BSAVE 37 9400 e024 e13a ... <ALBUM ALBUM> BSAVE 38 9800 e40c ea06 hmm BSAVE 39 9c00 e7f4 ea06 hmm source 40 a000 Album page source 41-45 a400 Adeste Fideles LCT 08Dec83 - 10Dec83 BSAVE 46 b800 e13a e4a6 Adeste Fideles source 47-50 5c00 unused BSAVE 51 cc00 e13a e288 Scale test BSAVE 52-55 d000 e13a ed30 Sailor's Hornpipe BSAVE 56 e000 e13a e322 Frere Jacques free 57 e400 BSAVE 58-59? e800 e13a e952 Boogie. ZITHER source 60-67 Sailor's Hornpipe BSAVE 68 11000 e13a e5c8 ?Sailor's Hornpipe or unused 69 source 70-71 Frere Jacques BSAVE 72 12000 e13a e32e ? 73-74 source 75-77 Ermuntre Dich, Mein Schwacher Geist BSAVE 78 13800 e13a e48e Ermuntre Dich free 79-80 free source 81-82 14400 Boogie BSAVE 83 14c00 e13a e34a fragment of Boogie? free 84-89 15000 free Detail of Screen 20 BSAVE header offs value purpose 00 bc8a load address 02 e288 dict pointer 04 39de CURRENT 06 e242 CURRENT @ 08 39de CONTEXT 0a e242 CONTEXT @ 0c d548 VOC-LINK 0e 7469 'ti' as a signature 10 unused 24 image 1000 bytes First word is .BLK back link >bc42 code field >8334 These would be entry points to the inner interpreter in PAD: 832E is DODOES (Used 13 times) 8334 is DOCOL (Used 437 times) Quote Link to comment Share on other sites More sharing options...
Tursi Posted September 26 Share Posted September 26 10 hours ago, Asmusr said: But I don't think Classic99 emulates the FORTi, at least it didn't sound like it. I also looked at the MAME implementation, and it appears that it has the enable bits for the PSGs reversed. A PSG should be on when the bit is off, AFAIK. No, it doesn't. It's tough to add hardware like that, I looked at it, but decided to wait till v4, if it's ever finished. I added FORTI support in Super Space Acer, so that required me to build hardware. The enable bits are really easy to understand once you realize that the address bits are just directly connected - so when the address bit is 0, that PSG is enabled. Assuming I got it right! Thierry has a good breakdown of it: https://www.unige.ch/medecine/nouspikel/ti99/forti.htm 2 Quote Link to comment Share on other sites More sharing options...
Asmusr Posted September 26 Share Posted September 26 3 hours ago, Tursi said: I added FORTI support in Super Space Acer, so that required me to build hardware. I didn't know that. Do you need to do anything to turn it on? Quote Link to comment Share on other sites More sharing options...
Tursi Posted September 27 Share Posted September 27 17 hours ago, Asmusr said: I didn't know that. Do you need to do anything to turn it on? Yes, it's in the config screen, but since I haven't released it I'd be surprised if you knew that. Quote Link to comment Share on other sites More sharing options...
Asmusr Posted September 28 Share Posted September 28 16 hours ago, Tursi said: Yes, it's in the config screen, but since I haven't released it I'd be surprised if you knew that. So it's something you plan to release in an updated version of Super Space Acer? Quote Link to comment Share on other sites More sharing options...
Tursi Posted Tuesday at 03:05 AM Share Posted Tuesday at 03:05 AM On 9/27/2024 at 11:15 PM, Asmusr said: So it's something you plan to release in an updated version of Super Space Acer? Yeah, it's finished. ArcadeShopper gets first dibs to sell carts for a few months before I release the ROM, but we're stalled on a shortage of UberGROM carts The game supports SID or ForTI for additional sound effects. 4 Quote Link to comment Share on other sites More sharing options...
RickyDean Posted Tuesday at 04:43 PM Share Posted Tuesday at 04:43 PM (edited) Retracted, don't have power. I was going to offer to test on my ubergroms. Edited Tuesday at 04:56 PM by RickyDean Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.