├── .gitignore ├── LICENSE ├── README.md ├── build.sh ├── data.asm ├── docs ├── TI-82 Stats - Power Socket Mod.pdf ├── changelog.txt ├── data │ ├── drumwave.png │ ├── favicon.ico │ ├── fxptns.png │ ├── idea.jpg │ ├── iedummy.js │ ├── invertabit1.png │ ├── invertabit2.png │ ├── invertabit3.jpg │ ├── keymap.jpg │ ├── main.css │ ├── noteptns.png │ ├── seq.png │ ├── tut1.png │ ├── tut2.png │ ├── tut3.png │ ├── tut4.png │ ├── tut5.png │ ├── underconstr.jpg │ ├── vars.png │ └── warn.jpg ├── headphone-amp │ ├── Houston Headphone Amp 2022 2.1.fzz │ ├── Houston Headphone Amp 2022 Gerber │ │ └── Houston Headphone Amp 2022 2.1.zip │ ├── README PLZ.txt │ ├── headphones_amp_and_pcb.jpg │ └── original │ │ ├── Houston Headphone amp 3.fz │ │ └── gerber │ │ ├── Houston Headphone amp 3.gbl │ │ ├── Houston Headphone amp 3.gbo │ │ ├── Houston Headphone amp 3.gbs │ │ ├── Houston Headphone amp 3.gm1 │ │ ├── Houston Headphone amp 3.gtl │ │ ├── Houston Headphone amp 3.gto │ │ ├── Houston Headphone amp 3.gts │ │ └── Houston Headphone amp 3.txt ├── houston_tracker_2-30_memo.pdf ├── line-mod-3.5mm │ ├── image0.jpeg │ ├── image1.jpeg │ └── image2.jpeg ├── manual.html └── manual.tex ├── font.asm ├── gfx.asm ├── include ├── scratchpad.inc ├── ti82.inc ├── ti82parcus.inc ├── ti83.inc ├── ti8xp.inc └── ti8xs.inc ├── init.asm ├── keyhand.asm ├── main.asm ├── mem.asm ├── player.asm ├── teststate.asm └── util.asm /.gitignore: -------------------------------------------------------------------------------- 1 | _BACKUP/ 2 | _build/ 3 | _bin/ 4 | _scripts/ 5 | *.sym 6 | *.aux 7 | *.log 8 | *.out 9 | *.toc 10 | *.synctex.gz 11 | manual.pdf 12 | test.sh 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, utz82 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of HoustonTracker2 nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HoustonTracker2 2 | A music editor for TI graphing calculators 3 | 4 | 5 | ### About 6 | 7 | HoustonTracker 2 is a software sequencer that enables you to create music on Texas Instruments graphing calculators. It uses the machines' communication port to output multi-channel 1-bit music. Its interface is inspired by popular trackers such as LSDJ, Famitracker, and Milkytracker. 8 | 9 | HT2 supports several models of the Z80-based line of TI calculators. It is mainly targeted at older, obsolete models like the TI-82, but also works on TI-83, 10 | TI-83Plus/SE, and TI-84Plus/SE. 11 | 12 | More information and online documentation can be found at 13 | http://irrlichtproject.de/houston 14 | 15 | Note that the online documentation applies to the stable version of HT2, for the beta version refer to the manual in the /docs folder in source. 16 | 17 | 18 | ### Features 19 | 20 | * 3 tone channels 21 | * 1 non-interrupting drum channel 22 | * up to 128 note patterns 23 | * up to 64 drum/fx patterns 24 | * sequence length up to 255 pattern rows 25 | * 16-bit frequency precision 26 | * 8-bit speed precision, can be configured per step 27 | * various effects, including: 28 | * L/C/R stereo hard-panning for tone and drum channels 29 | * 8-bit duty cycle control 30 | * duty cycle sweep 31 | * 2 user definable samples 32 | * up to 8 savestates 33 | * edit during playback 34 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | command -v pasmo >/dev/null 2>&1 || { echo >&2 "Pasmo assembler not found. Aborting."; exit 1; } 4 | 5 | if [ ! -e _bin/oysterpac/oysterpac ] ; then 6 | echo "missing oysterpac, grab it from github..." 7 | command -v git >/dev/null 2>&1 || \ 8 | { echo >&2 "Need git to fetch oysterpac. Please install git, or obtain oysterpac manually and copy it to _bin/oysterpac"; \ 9 | exit 1; } 10 | mkdir -p _bin && cd _bin 11 | ping -c1 -q github.com >/dev/null 2>&1 || { echo >&2 "Cannot reach github.com. Aborting."; cd ..; exit 1; } 12 | git clone https://github.com/utz82/oysterpac.git || { echo >&2 "Failed to clone oysterpac repository. Aborting."; cd ..; exit 1; } 13 | cd oysterpac 14 | g++ -O2 -s -Wall -o oysterpac oysterpac.cpp || { echo >&2 "Failed to compile oysterpac. Aborting."; cd ../..; exit 1; } 15 | cd ../.. 16 | fi 17 | 18 | mkdir -p _build 19 | [ ! -e _build/oysterpac ] && cp _bin/oysterpac/oysterpac _build/oysterpac 20 | 21 | case $1 in 22 | -82) MODEL=1 ;; 23 | -83) MODEL=2 ;; 24 | -8x) MODEL=3 ;; 25 | -82p) MODEL=4 ;; 26 | -82parcus) MODEL=4 ;; 27 | -8xs) MODEL=5 ;; 28 | -8xsmall) MODEL=5 ;; 29 | esac 30 | 31 | FILENAMES=( none ht2.82p ht2.83p ht2.8xp ht2p.82p ht2s.8xp ) 32 | 33 | for i in {1..5} ; do 34 | [[ -z $MODEL || "$MODEL" = "$i" ]] && echo "building ${FILENAMES[$i]}" \ 35 | && pasmo --equ MODEL=$i --alocal main.asm _build/main.bin main.sym && cd _build \ 36 | && ./oysterpac main.bin ${FILENAMES[$i]} ht2 && cd .. 37 | done 38 | 39 | [ -e _build/oysterpac ] && rm _build/oysterpac 40 | [ -e _build/main.bin ] && rm _build/main.bin 41 | 42 | for ARG in $* ; do 43 | if [ "$ARG" = "-docs" ] ; then 44 | command -v pdflatex >/dev/null 2>&1 || { echo >&2 "Need pdflatex to build docs. Aborting."; exit 1; } 45 | cd docs; pdflatex -halt-on-error manual && pdflatex -halt-on-error manual; cd .. 46 | fi 47 | [[ "$ARG" = "-test" && -e _scripts/test.sh ]] && source "_scripts/test.sh" 48 | done 49 | 50 | exit 0; 51 | -------------------------------------------------------------------------------- /data.asm: -------------------------------------------------------------------------------- 1 | ;************************************************************************************ 2 | ;TABLES AND INCLUDES 3 | ;************************************************************************************ 4 | 5 | baseCounterLUT ;counter values for octave 6, all other counter values are derived from this 6 | 7 | ;dw #4000, #43CE, #47D6, #4C1C, #50A3, #556E, #5A83, #5FE4, #6598, #6BA3, #7209, #78D1 8 | ;dw #2000, #21E7, #23EB, #260E, #2851, #2AB7, #2D41, #2FF2, #32CC, #35D1, #3905, #3C68 9 | ;dw #14b8, #15f3, #1741, #18a3, #1a1a, #1ba8, #1d4d, #1f0b, #20e3, #22d8, #24ea, #271c 10 | ;dw #1f6f, #214e, #2349, #2562, #279b, #29f6, #2c74, #2f19, #31e6, #34de, #3802, #3b57 11 | dw #1f86, #2166, #2362, #257d, #27b8, #2a14, #2c95, #2f3b, #320a, #3504, #382b, #3b82 12 | 13 | font 14 | include "font.asm" 15 | 16 | htlogo ;the HT2 logo 17 | db %11110101 18 | db %11110001 19 | db %11110101 20 | db %11111111 21 | db %11111111 22 | 23 | db %00010011 24 | db %10111101 25 | db %10111011 26 | db %11110001 27 | db %11111111 28 | 29 | varmsgs ;global var names (right side of screen) 30 | 31 | db CHAR_L,CHAR_P ;LP 32 | db CHAR_S,CHAR_P ;SP(D) 33 | db CHAR_B,CHAR_S ;BS 34 | db CHAR_B,CHAR_E ;BE 35 | 36 | notenames 37 | db CHAR_C,CHAR_DASH ;c 38 | db CHAR_C,CHAR_SHARP ;c# 39 | db CHAR_D,CHAR_DASH ;d 40 | db CHAR_D,CHAR_SHARP ;d# 41 | db CHAR_E,CHAR_DASH ;e 42 | db CHAR_F,CHAR_DASH ;f 43 | db CHAR_F,CHAR_SHARP ;f# 44 | db CHAR_G,CHAR_DASH ;g 45 | db CHAR_G,CHAR_SHARP ;g# 46 | db CHAR_A,CHAR_DASH ;a 47 | db CHAR_A,CHAR_SHARP ;a# 48 | db CHAR_B,CHAR_DASH ;b 49 | 50 | 51 | 52 | 53 | IF ((HIGH($))<(HIGH($+30))) 54 | org 256*(1+(HIGH($))) ;align to next page if necessary 55 | .WARNING kjumptab or notevals crosses page boundary, realigned to next page 56 | ENDIF 57 | 58 | kjumptab ;jump table for keyhandler. MAY NOT CROSS PAGE BOUNDARY! 59 | dw kdown 60 | dw kleft 61 | dw kright 62 | dw kup 63 | dw kpdown 64 | dw kpleft 65 | dw kpright 66 | dw kpup 67 | dw kfdown 68 | dw kfleft 69 | dw kfright 70 | dw kfup 71 | ktest equ $-1 72 | ; IF ((HIGH(kjumptab))<(HIGH(ktest))) 73 | ; .ERROR kjumptab crosses page boundary 74 | ; ENDIF 75 | 76 | notevals equ $-#a ;LUT for note name -> val conversion 77 | db 10 ;A 78 | db 12 ;B 79 | db 1 ;C 80 | db 3 ;D 81 | db 5 ;E 82 | db 6 ;F 83 | db 8 ;G 84 | ttest equ $-1 85 | ;IF ((HIGH(notevals))<(HIGH(ttest))) 86 | ;.ERROR notevals crosses page boundary 87 | ;ENDIF 88 | -------------------------------------------------------------------------------- /docs/TI-82 Stats - Power Socket Mod.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utz82/HoustonTracker2/1915cea4016d5e55dcb5f7f782b2822d642e216c/docs/TI-82 Stats - Power Socket Mod.pdf -------------------------------------------------------------------------------- /docs/changelog.txt: -------------------------------------------------------------------------------- 1 | 2 | version 2.30.00 3 | =============== 4 | 5 | NEW/CHANGES 6 | 7 | - note table tuned to ~440 Hz (and some notes produce more useful noise fx as a result) 8 | - ch2 duty sweep (5xx, xx > 0x80) now has a configurable parameter (xx & 0x7f) 9 | - effect 7xx (auto-chord) now has two modes: unsynced (regular) and synced (octave chord) 10 | - channel volumes rebalanced 11 | - slowed down ch3 slides, 3xx now works like 2xx (xx is no longer inverse) 12 | - 9xx no longer disables 3xx 13 | - new effect: ch3 grind (enabled with 6xx, xx>0x80) 14 | - old Axx has been ditched 15 | - new Axx effect: set phase offset ch3 16 | - Synth Mode: hold current row 17 | - add display of last used savestate 18 | - add pattern loop playback mode 19 | 20 | BUGFIXES 21 | 22 | - fixed user drum input glitch 23 | - fixed major bug in keyhandler 24 | - reset player when clearing worktune 25 | 26 | 27 | 28 | version 2.20 29 | ================== 30 | 31 | NEW/CHANGES 32 | 33 | - new effect: 7xx - auto chord ch2 34 | - Exx is now the "Extended" fx command - execute up to 5 fx commands at once (old E00..E03 is now E80..E83) 35 | - Bxy now has added "loop section" function 36 | - more fine-grained tempo control 37 | - Copy/Paste keys are arranged in a more consistent/safe manner (check the manual for details!) 38 | - (somewhat) reduced noise during row transitions 39 | - improved fx handling 40 | 41 | BUGFIXES 42 | 43 | - fixed wrong Drum panning (was inverted) 44 | - faulty executable checksum calculation fixed (was causing errors with TI-Connect) 45 | 46 | 47 | 48 | version 2.10 49 | ============ 50 | 51 | NEW/CHANGES 52 | 53 | - channel 1 now has variable duty cycle, too 54 | - new effect: 4xx - set duty/noise mode ch1 55 | - old 4xx (toggle duty cycle sweep) has been merged in to 5xx (set duty ch2) 56 | - old Cxx (set drum mode) is now Dxx 57 | - old Dxx (set vol ch1/drums) has been removed (no longer possible for technical reasons) 58 | - new effect: 8xx - execute note table ch3 59 | - new effect: 9xx - glitch channel 3. 60 | - new Cxx effect: note cut ch1 61 | - TI-82 Parcus/OS 19.006 support 62 | - ALPHA mode is now one-shot, ie. it is turned off after an ALPHA mode action has been performed 63 | - sound loop now has cycle-exact timing except if drum modes 2x-4x are used 64 | - 3xx now uses inverse values (0xff = slowest setting), and is deactivated with 300 instead of 200. 65 | The old 300 effect can be achieved with command 9FF instead. 66 | - 2xx/3xx no longer trigger on rest notes. 67 | - "glitchy" drum modes no longer output sound on rows without a drum trigger 68 | - AutoInc is now off by default 69 | 70 | 71 | BUGFIXES 72 | 73 | - fixed recovery from failed save attempt 74 | - fx pattern 0x3f was previously lost during save, fixed 75 | - note pattern 0x7f was inaccessible from sequence screen, fixed 76 | - fixed broken loop point setting 77 | - improved keypad debouncing on Plus models 78 | - mode indicators were incorrect after loading/zapping a tune, fixed 79 | 80 | 81 | version 2.00 82 | ============ 83 | 84 | - initial public release 85 | -------------------------------------------------------------------------------- /docs/data/drumwave.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utz82/HoustonTracker2/1915cea4016d5e55dcb5f7f782b2822d642e216c/docs/data/drumwave.png -------------------------------------------------------------------------------- /docs/data/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utz82/HoustonTracker2/1915cea4016d5e55dcb5f7f782b2822d642e216c/docs/data/favicon.ico -------------------------------------------------------------------------------- /docs/data/fxptns.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utz82/HoustonTracker2/1915cea4016d5e55dcb5f7f782b2822d642e216c/docs/data/fxptns.png -------------------------------------------------------------------------------- /docs/data/idea.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utz82/HoustonTracker2/1915cea4016d5e55dcb5f7f782b2822d642e216c/docs/data/idea.jpg -------------------------------------------------------------------------------- /docs/data/iedummy.js: -------------------------------------------------------------------------------- 1 | //definining html5 elements for dumb browsers like IE 2 | 3 | document.createElement('article'); 4 | document.createElement('nav'); 5 | document.createElement('footer'); 6 | document.createElement('section'); 7 | document.createElement('time'); -------------------------------------------------------------------------------- /docs/data/invertabit1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utz82/HoustonTracker2/1915cea4016d5e55dcb5f7f782b2822d642e216c/docs/data/invertabit1.png -------------------------------------------------------------------------------- /docs/data/invertabit2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utz82/HoustonTracker2/1915cea4016d5e55dcb5f7f782b2822d642e216c/docs/data/invertabit2.png -------------------------------------------------------------------------------- /docs/data/invertabit3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utz82/HoustonTracker2/1915cea4016d5e55dcb5f7f782b2822d642e216c/docs/data/invertabit3.jpg -------------------------------------------------------------------------------- /docs/data/keymap.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utz82/HoustonTracker2/1915cea4016d5e55dcb5f7f782b2822d642e216c/docs/data/keymap.jpg -------------------------------------------------------------------------------- /docs/data/main.css: -------------------------------------------------------------------------------- 1 | div.mega { 2 | background-color: #ffffff; 3 | width: 100%; 4 | font-family: Arial, Helvetica, sans-serif; 5 | font-size: 48px; 6 | font-weight: bold; 7 | } 8 | 9 | div.header { 10 | background-color: #ffffff; 11 | width: 100%; 12 | font-family: Arial, Helvetica, sans-serif; 13 | font-size: 36px; 14 | font-weight: bold; 15 | page-break-before: always; 16 | } 17 | 18 | div.subheader { 19 | background-color: #ffffff; 20 | width: 100%; 21 | font-family: Arial, Helvetica, sans-serif; 22 | font-size: 24px; 23 | font-weight: bold; 24 | } 25 | 26 | div.subsubheader { 27 | background-color: #ffffff; 28 | width: 100%; 29 | font-family: Arial, Helvetica, sans-serif; 30 | font-size: 20px; 31 | font-weight: bold; 32 | } 33 | 34 | div.subsubsubheader { 35 | background-color: #ffffff; 36 | width: 100%; 37 | font-family: Arial, Helvetica, sans-serif; 38 | font-size: 16px; 39 | font-weight: bold; 40 | } 41 | 42 | div.minor { 43 | background-color: #ffffff; 44 | width: 100%; 45 | font-family: Arial, Helvetica, sans-serif; 46 | font-size: 16px; 47 | font-weight: bold; 48 | font-style: italic; 49 | } 50 | 51 | div.main { 52 | background-color: #ffffff; 53 | width: 80%; 54 | font-family: Arial, Helvetica, sans-serif; 55 | font-size: 16px; 56 | } 57 | 58 | div.warn { 59 | background-color: #ffffff; 60 | color: #ff0000; 61 | width: 80%; 62 | font-family: Arial, Helvetica, sans-serif; 63 | font-size: 16px; 64 | font-weight: bold; 65 | } 66 | 67 | div.license { 68 | margin: 10px; 69 | padding: 10px; 70 | background-color: #dddddd; 71 | 72 | font-family: monospace; 73 | font-size: 12px; 74 | } 75 | 76 | b { 77 | font-weight: bold; 78 | } 79 | 80 | a { 81 | color: #0000ff; 82 | text-decoration: none; 83 | } 84 | 85 | a:hover { 86 | background-color: #0000ff; 87 | color: #ffffff; 88 | text-decoration: none; 89 | } 90 | 91 | table { 92 | border-collapse: collapse; 93 | } 94 | 95 | 96 | table, th, td { 97 | border: 1px solid black; 98 | } 99 | 100 | td { 101 | padding: 4px; 102 | } 103 | 104 | th { 105 | font-weight: bold; 106 | } -------------------------------------------------------------------------------- /docs/data/noteptns.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utz82/HoustonTracker2/1915cea4016d5e55dcb5f7f782b2822d642e216c/docs/data/noteptns.png -------------------------------------------------------------------------------- /docs/data/seq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utz82/HoustonTracker2/1915cea4016d5e55dcb5f7f782b2822d642e216c/docs/data/seq.png -------------------------------------------------------------------------------- /docs/data/tut1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utz82/HoustonTracker2/1915cea4016d5e55dcb5f7f782b2822d642e216c/docs/data/tut1.png -------------------------------------------------------------------------------- /docs/data/tut2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utz82/HoustonTracker2/1915cea4016d5e55dcb5f7f782b2822d642e216c/docs/data/tut2.png -------------------------------------------------------------------------------- /docs/data/tut3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utz82/HoustonTracker2/1915cea4016d5e55dcb5f7f782b2822d642e216c/docs/data/tut3.png -------------------------------------------------------------------------------- /docs/data/tut4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utz82/HoustonTracker2/1915cea4016d5e55dcb5f7f782b2822d642e216c/docs/data/tut4.png -------------------------------------------------------------------------------- /docs/data/tut5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utz82/HoustonTracker2/1915cea4016d5e55dcb5f7f782b2822d642e216c/docs/data/tut5.png -------------------------------------------------------------------------------- /docs/data/underconstr.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utz82/HoustonTracker2/1915cea4016d5e55dcb5f7f782b2822d642e216c/docs/data/underconstr.jpg -------------------------------------------------------------------------------- /docs/data/vars.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utz82/HoustonTracker2/1915cea4016d5e55dcb5f7f782b2822d642e216c/docs/data/vars.png -------------------------------------------------------------------------------- /docs/data/warn.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utz82/HoustonTracker2/1915cea4016d5e55dcb5f7f782b2822d642e216c/docs/data/warn.jpg -------------------------------------------------------------------------------- /docs/headphone-amp/Houston Headphone Amp 2022 2.1.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utz82/HoustonTracker2/1915cea4016d5e55dcb5f7f782b2822d642e216c/docs/headphone-amp/Houston Headphone Amp 2022 2.1.fzz -------------------------------------------------------------------------------- /docs/headphone-amp/Houston Headphone Amp 2022 Gerber/Houston Headphone Amp 2022 2.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utz82/HoustonTracker2/1915cea4016d5e55dcb5f7f782b2822d642e216c/docs/headphone-amp/Houston Headphone Amp 2022 Gerber/Houston Headphone Amp 2022 2.1.zip -------------------------------------------------------------------------------- /docs/headphone-amp/README PLZ.txt: -------------------------------------------------------------------------------- 1 | INVERT-A-BIT Headphones Amp 2022 Update 2 | By skate323k137 / AK-DJ 3 | 4 | In this folder you will find the Fritzing project files, and Gerber archive, for an updated version of the Invert-a-bit headphones amp for HoustonTracker2. Updates to the original design were to expand the board adding I/O jacks and power options. 5 | 6 | Updates 2022 March: 7 | Added power switch ("Breadboard Compatible") 8 | Added 9V DC "Breadboard Compatible" Barrel connector, accepts a standard 9V center negative power supply, i.e. from most guitar pedals. 9 | Added solder terminals for optional 9V battery (DC Jack disconnects battery positive when inserted, so DC Jack power takes priority) 10 | Note: The barrel connector must be installed for the 9v battery circuit to be completed. 11 | Added 3.5mm barrel jacks for input and output (use a 2.5mm to 3.5mm headphones cable to connect the calc to the input) 12 | Added spots for optional RCA jacks. This version will disconnect RCA output when a jack is present in the headphones output connector. 13 | Original power terminals labelled TP1/TP2 can be used for a 2-wire voltmeter, which can be affixed (glued) to the DIP IC. 14 | 15 | If normal PCB Standoff feet are attached to the design there should be just enough room underneath for a 9V battery, but don't expect amazing life. Still, this design fits well within the width of a TI-83 so if you design an enclosoure it may serve well for some travel. 16 | 17 | Updates 2022 September: 18 | Rerouted traces 19 | Adjusted/increased trace sizes 20 | Fixed positioning of PCB Feet holes 21 | Fixed relevent silkscreens to be easier to read with headphones/power jacks installed. 22 | 23 | NOTE: 24 | 25 | The original design and gerbers from Snorkel can be found in the 'original' subdirectory with this document. 26 | The original note from Snorkel (who designed the real logic of this unit, and to whom I owe many thanks for his kindness) is below: 27 | 28 | -- 29 | 30 | Hello! 31 | 32 | So you decided to build a headphone amp for your texas instruments calculator! Good choice! 33 | 34 | This is not really a normal headphone amp. It will only work with 1-bit signals. If you manage to put "normal music" through the "amp" 35 | it will just be turned in to a squarewave and probably sound pretty distorted. 36 | This is because the heart of the thing is a cmos logic chip called CD4069 and all it does is take the squares 37 | coming from the calculator, inverts their phase and buffer them so that it can drive a couple of headphones. 38 | The PCB also includes a lowpass filter that tastfully cuts out a bit of the high frequency ripple coming from the calc. 39 | But no too much! =) 40 | 41 | This folder contains all the stuff you should need to build your own amp. Either with the fritzing files or if you wanna order your 42 | own pcb just use the Gerber files at your favorite pcb-manufacturer. 43 | 44 | I take no responsibility for this thing. If your stuff breaks when using or building this its your fault. 45 | It worked well for me and its a pretty easy build so you should be fine. (FINGERS CROSSED) 46 | 47 | Hope you'll have many fun hours on the train or where ever you wanna sit with your calc. 48 | Enjoy! 49 | 50 | /Niklas 51 | -- 52 | -------------------------------------------------------------------------------- /docs/headphone-amp/headphones_amp_and_pcb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utz82/HoustonTracker2/1915cea4016d5e55dcb5f7f782b2822d642e216c/docs/headphone-amp/headphones_amp_and_pcb.jpg -------------------------------------------------------------------------------- /docs/headphone-amp/original/gerber/Houston Headphone amp 3.gbl: -------------------------------------------------------------------------------- 1 | G04 MADE WITH FRITZING* 2 | G04 WWW.FRITZING.ORG* 3 | G04 DOUBLE SIDED* 4 | G04 HOLES PLATED* 5 | G04 CONTOUR ON CENTER OF CONTOUR VECTOR* 6 | %ASAXBY*% 7 | %FSLAX23Y23*% 8 | %MOIN*% 9 | %OFA0B0*% 10 | %SFA1.0B1.0*% 11 | %ADD10C,0.062992*% 12 | %ADD11C,0.039370*% 13 | %ADD12C,0.075000*% 14 | %ADD13C,0.070000*% 15 | %ADD14C,0.078000*% 16 | %ADD15C,0.157480*% 17 | %ADD16R,0.062992X0.062992*% 18 | %ADD17R,0.075000X0.075000*% 19 | %ADD18R,0.078000X0.078000*% 20 | %ADD19C,0.024000*% 21 | %LNCOPPER0*% 22 | G90* 23 | G70* 24 | G54D10* 25 | X226Y819D03* 26 | X226Y721D03* 27 | G54D11* 28 | X1020Y410D03* 29 | X684Y1442D03* 30 | G54D12* 31 | X526Y1321D03* 32 | X826Y1321D03* 33 | X526Y1221D03* 34 | X826Y1221D03* 35 | X526Y1121D03* 36 | X826Y1121D03* 37 | X526Y1021D03* 38 | X826Y1021D03* 39 | X526Y921D03* 40 | X826Y921D03* 41 | X526Y821D03* 42 | X826Y821D03* 43 | X526Y721D03* 44 | X826Y721D03* 45 | X926Y1921D03* 46 | X1326Y1921D03* 47 | X1126Y1621D03* 48 | X1126Y1221D03* 49 | X526Y1621D03* 50 | X926Y1621D03* 51 | X426Y321D03* 52 | X826Y321D03* 53 | X526Y1521D03* 54 | X926Y1521D03* 55 | X426Y521D03* 56 | X826Y521D03* 57 | X426Y221D03* 58 | X826Y221D03* 59 | X426Y421D03* 60 | X826Y421D03* 61 | G54D13* 62 | X1026Y921D03* 63 | X1126Y921D03* 64 | X1026Y1021D03* 65 | X1126Y1021D03* 66 | G54D12* 67 | X326Y1621D03* 68 | X126Y1621D03* 69 | X1326Y621D03* 70 | X1126Y621D03* 71 | X1226Y219D03* 72 | X1026Y219D03* 73 | G54D14* 74 | X1526Y1321D03* 75 | X1526Y1121D03* 76 | X1526Y921D03* 77 | X1326Y1321D03* 78 | X1326Y1121D03* 79 | X1326Y921D03* 80 | X1526Y521D03* 81 | X1526Y421D03* 82 | X1526Y321D03* 83 | X1526Y1821D03* 84 | X1526Y1721D03* 85 | X1526Y1621D03* 86 | X426Y1921D03* 87 | X626Y1921D03* 88 | G54D15* 89 | X126Y121D03* 90 | X1526Y121D03* 91 | X126Y2021D03* 92 | X1526Y2021D03* 93 | G54D16* 94 | X226Y819D03* 95 | G54D17* 96 | X526Y1321D03* 97 | X326Y1621D03* 98 | X1326Y621D03* 99 | X1226Y219D03* 100 | G54D18* 101 | X1526Y1321D03* 102 | X1326Y1321D03* 103 | G54D19* 104 | X182Y979D02* 105 | X208Y1197D01* 106 | D02* 107 | X219Y845D02* 108 | X182Y979D01* 109 | D02* 110 | X308Y1363D02* 111 | X502Y1504D01* 112 | D02* 113 | X208Y1197D02* 114 | X308Y1363D01* 115 | D02* 116 | X1502Y1302D02* 117 | X1404Y1226D01* 118 | X1404Y1226D02* 119 | X1393Y352D01* 120 | D02* 121 | X1326Y222D02* 122 | X1255Y220D01* 123 | D02* 124 | X1393Y352D02* 125 | X1326Y222D01* 126 | D02* 127 | X925Y522D02* 128 | X1100Y608D01* 129 | D02* 130 | X925Y422D02* 131 | X925Y522D01* 132 | D02* 133 | X846Y341D02* 134 | X925Y422D01* 135 | D02* 136 | X535Y1648D02* 137 | X616Y1892D01* 138 | D02* 139 | X1513Y1093D02* 140 | X1452Y962D01* 141 | X1452Y962D02* 142 | X1452Y458D01* 143 | X1452Y458D02* 144 | X1499Y434D01* 145 | D02* 146 | X505Y841D02* 147 | X424Y920D01* 148 | D02* 149 | X424Y920D02* 150 | X424Y1020D01* 151 | D02* 152 | X424Y1020D02* 153 | X497Y1021D01* 154 | D02* 155 | X497Y1221D02* 156 | X424Y1220D01* 157 | D02* 158 | X424Y1220D02* 159 | X424Y1120D01* 160 | D02* 161 | X424Y1120D02* 162 | X505Y1041D01* 163 | D02* 164 | X449Y237D02* 165 | X492Y266D01* 166 | X492Y266D02* 167 | X524Y522D01* 168 | D02* 169 | X524Y522D02* 170 | X424Y719D01* 171 | D02* 172 | X424Y719D02* 173 | X424Y819D01* 174 | D02* 175 | X424Y819D02* 176 | X497Y820D01* 177 | D02* 178 | X804Y1040D02* 179 | X756Y1082D01* 180 | D02* 181 | X756Y1082D02* 182 | X756Y1178D01* 183 | D02* 184 | X756Y1178D02* 185 | X801Y1206D01* 186 | D02* 187 | X847Y840D02* 188 | X900Y890D01* 189 | D02* 190 | X900Y890D02* 191 | X900Y986D01* 192 | D02* 193 | X900Y986D02* 194 | X851Y1009D01* 195 | D02* 196 | X1097Y1221D02* 197 | X854Y1221D01* 198 | D02* 199 | X817Y548D02* 200 | X780Y662D01* 201 | D02* 202 | X780Y662D02* 203 | X756Y674D01* 204 | D02* 205 | X756Y674D02* 206 | X756Y794D01* 207 | D02* 208 | X756Y794D02* 209 | X799Y810D01* 210 | D02* 211 | X1097Y1621D02* 212 | X954Y1621D01* 213 | D02* 214 | X1226Y920D02* 215 | X1226Y820D01* 216 | D02* 217 | X1144Y1002D02* 218 | X1226Y920D01* 219 | D02* 220 | X1226Y820D02* 221 | X1217Y567D01* 222 | D02* 223 | X1126Y422D02* 224 | X1039Y245D01* 225 | D02* 226 | X1125Y422D02* 227 | X1126Y422D01* 228 | D02* 229 | X1217Y567D02* 230 | X1125Y422D01* 231 | D02* 232 | X805Y441D02* 233 | X725Y522D01* 234 | D02* 235 | X725Y522D02* 236 | X696Y746D01* 237 | D02* 238 | X696Y746D02* 239 | X546Y900D01* 240 | D02* 241 | X1315Y1894D02* 242 | X1188Y1562D01* 243 | X1188Y1562D02* 244 | X996Y1466D01* 245 | D02* 246 | X996Y1466D02* 247 | X553Y1329D01* 248 | D02* 249 | X1304Y942D02* 250 | X1125Y1120D01* 251 | D02* 252 | X1125Y1120D02* 253 | X1005Y1120D01* 254 | D02* 255 | X1005Y1120D02* 256 | X1020Y1046D01* 257 | D02* 258 | X1538Y948D02* 259 | X1596Y1082D01* 260 | X1596Y1082D02* 261 | X1596Y1394D01* 262 | X1596Y1394D02* 263 | X1260Y1394D01* 264 | X1260Y1394D02* 265 | X1260Y1058D01* 266 | X1260Y1058D02* 267 | X1313Y948D01* 268 | D02* 269 | X535Y694D02* 270 | X725Y122D01* 271 | D02* 272 | X725Y122D02* 273 | X925Y122D01* 274 | D02* 275 | X925Y122D02* 276 | X1014Y392D01* 277 | D02* 278 | X1500Y1806D02* 279 | X1452Y1778D01* 280 | X1452Y1778D02* 281 | X1452Y1586D01* 282 | X1452Y1586D02* 283 | X1596Y1394D01* 284 | D02* 285 | X309Y1597D02* 286 | X84Y1274D01* 287 | X84Y1274D02* 288 | X84Y746D01* 289 | X84Y746D02* 290 | X199Y725D01* 291 | D02* 292 | X400Y433D02* 293 | X348Y458D01* 294 | X348Y458D02* 295 | X324Y1220D01* 296 | D02* 297 | X324Y1220D02* 298 | X468Y1394D01* 299 | X468Y1394D02* 300 | X665Y1438D01* 301 | G04 End of Copper0* 302 | M02* -------------------------------------------------------------------------------- /docs/headphone-amp/original/gerber/Houston Headphone amp 3.gbo: -------------------------------------------------------------------------------- 1 | G04 MADE WITH FRITZING* 2 | G04 WWW.FRITZING.ORG* 3 | G04 DOUBLE SIDED* 4 | G04 HOLES PLATED* 5 | G04 CONTOUR ON CENTER OF CONTOUR VECTOR* 6 | %ASAXBY*% 7 | %FSLAX23Y23*% 8 | %MOIN*% 9 | %OFA0B0*% 10 | %SFA1.0B1.0*% 11 | %ADD10R,1.653540X2.125980X1.637540X2.109980*% 12 | %ADD11C,0.008000*% 13 | %LNSILK0*% 14 | G90* 15 | G70* 16 | G54D11* 17 | X4Y2122D02* 18 | X1650Y2122D01* 19 | X1650Y4D01* 20 | X4Y4D01* 21 | X4Y2122D01* 22 | D02* 23 | G04 End of Silk0* 24 | M02* -------------------------------------------------------------------------------- /docs/headphone-amp/original/gerber/Houston Headphone amp 3.gbs: -------------------------------------------------------------------------------- 1 | G04 MADE WITH FRITZING* 2 | G04 WWW.FRITZING.ORG* 3 | G04 DOUBLE SIDED* 4 | G04 HOLES PLATED* 5 | G04 CONTOUR ON CENTER OF CONTOUR VECTOR* 6 | %ASAXBY*% 7 | %FSLAX23Y23*% 8 | %MOIN*% 9 | %OFA0B0*% 10 | %SFA1.0B1.0*% 11 | %ADD10C,0.072992*% 12 | %ADD11C,0.049370*% 13 | %ADD12C,0.085000*% 14 | %ADD13C,0.080000*% 15 | %ADD14C,0.088000*% 16 | %ADD15C,0.167480*% 17 | %ADD16R,0.072992X0.072992*% 18 | %ADD17R,0.085000X0.085000*% 19 | %ADD18R,0.088000X0.088000*% 20 | %LNMASK0*% 21 | G90* 22 | G70* 23 | G54D10* 24 | X226Y819D03* 25 | X226Y721D03* 26 | G54D11* 27 | X1020Y410D03* 28 | X684Y1442D03* 29 | G54D12* 30 | X526Y1321D03* 31 | X826Y1321D03* 32 | X526Y1221D03* 33 | X826Y1221D03* 34 | X526Y1121D03* 35 | X826Y1121D03* 36 | X526Y1021D03* 37 | X826Y1021D03* 38 | X526Y921D03* 39 | X826Y921D03* 40 | X526Y821D03* 41 | X826Y821D03* 42 | X526Y721D03* 43 | X826Y721D03* 44 | X926Y1921D03* 45 | X1326Y1921D03* 46 | X1126Y1621D03* 47 | X1126Y1221D03* 48 | X526Y1621D03* 49 | X926Y1621D03* 50 | X426Y321D03* 51 | X826Y321D03* 52 | X526Y1521D03* 53 | X926Y1521D03* 54 | X426Y521D03* 55 | X826Y521D03* 56 | X426Y221D03* 57 | X826Y221D03* 58 | X426Y421D03* 59 | X826Y421D03* 60 | G54D13* 61 | X1026Y921D03* 62 | X1126Y921D03* 63 | X1026Y1021D03* 64 | X1126Y1021D03* 65 | G54D12* 66 | X326Y1621D03* 67 | X126Y1621D03* 68 | X1326Y621D03* 69 | X1126Y621D03* 70 | X1226Y219D03* 71 | X1026Y219D03* 72 | G54D14* 73 | X1526Y1321D03* 74 | X1526Y1121D03* 75 | X1526Y921D03* 76 | X1326Y1321D03* 77 | X1326Y1121D03* 78 | X1326Y921D03* 79 | X1526Y521D03* 80 | X1526Y421D03* 81 | X1526Y321D03* 82 | X1526Y1821D03* 83 | X1526Y1721D03* 84 | X1526Y1621D03* 85 | X426Y1921D03* 86 | X626Y1921D03* 87 | G54D15* 88 | X126Y121D03* 89 | X1526Y121D03* 90 | X126Y2021D03* 91 | X1526Y2021D03* 92 | G54D16* 93 | X226Y819D03* 94 | G54D17* 95 | X526Y1321D03* 96 | X326Y1621D03* 97 | X1326Y621D03* 98 | X1226Y219D03* 99 | G54D18* 100 | X1526Y1321D03* 101 | X1326Y1321D03* 102 | G04 End of Mask0* 103 | M02* -------------------------------------------------------------------------------- /docs/headphone-amp/original/gerber/Houston Headphone amp 3.gm1: -------------------------------------------------------------------------------- 1 | G04 MADE WITH FRITZING* 2 | G04 WWW.FRITZING.ORG* 3 | G04 DOUBLE SIDED* 4 | G04 HOLES PLATED* 5 | G04 CONTOUR ON CENTER OF CONTOUR VECTOR* 6 | %ASAXBY*% 7 | %FSLAX23Y23*% 8 | %MOIN*% 9 | %OFA0B0*% 10 | %SFA1.0B1.0*% 11 | %ADD10R,1.653540X2.125980*% 12 | %ADD11C,0.008000*% 13 | %ADD10C,0.008*% 14 | %LNCONTOUR*% 15 | G90* 16 | G70* 17 | G54D10* 18 | G54D11* 19 | X4Y2122D02* 20 | X1650Y2122D01* 21 | X1650Y4D01* 22 | X4Y4D01* 23 | X4Y2122D01* 24 | D02* 25 | G04 End of contour* 26 | M02* -------------------------------------------------------------------------------- /docs/headphone-amp/original/gerber/Houston Headphone amp 3.gtl: -------------------------------------------------------------------------------- 1 | G04 MADE WITH FRITZING* 2 | G04 WWW.FRITZING.ORG* 3 | G04 DOUBLE SIDED* 4 | G04 HOLES PLATED* 5 | G04 CONTOUR ON CENTER OF CONTOUR VECTOR* 6 | %ASAXBY*% 7 | %FSLAX23Y23*% 8 | %MOIN*% 9 | %OFA0B0*% 10 | %SFA1.0B1.0*% 11 | %ADD10C,0.062992*% 12 | %ADD11C,0.039370*% 13 | %ADD12C,0.075000*% 14 | %ADD13C,0.070000*% 15 | %ADD14C,0.078000*% 16 | %ADD15C,0.157480*% 17 | %ADD16R,0.062992X0.062992*% 18 | %ADD17R,0.075000X0.075000*% 19 | %ADD18R,0.078000X0.078000*% 20 | %ADD19C,0.024000*% 21 | %LNCOPPER1*% 22 | G90* 23 | G70* 24 | G54D10* 25 | X226Y819D03* 26 | X226Y721D03* 27 | G54D11* 28 | X1020Y410D03* 29 | X684Y1442D03* 30 | G54D12* 31 | X526Y1321D03* 32 | X826Y1321D03* 33 | X526Y1221D03* 34 | X826Y1221D03* 35 | X526Y1121D03* 36 | X826Y1121D03* 37 | X526Y1021D03* 38 | X826Y1021D03* 39 | X526Y921D03* 40 | X826Y921D03* 41 | X526Y821D03* 42 | X826Y821D03* 43 | X526Y721D03* 44 | X826Y721D03* 45 | X926Y1921D03* 46 | X1326Y1921D03* 47 | X1126Y1621D03* 48 | X1126Y1221D03* 49 | X526Y1621D03* 50 | X926Y1621D03* 51 | X426Y321D03* 52 | X826Y321D03* 53 | X526Y1521D03* 54 | X926Y1521D03* 55 | X426Y521D03* 56 | X826Y521D03* 57 | X426Y221D03* 58 | X826Y221D03* 59 | X426Y421D03* 60 | X826Y421D03* 61 | G54D13* 62 | X1026Y921D03* 63 | X1126Y921D03* 64 | X1026Y1021D03* 65 | X1126Y1021D03* 66 | G54D12* 67 | X326Y1621D03* 68 | X126Y1621D03* 69 | X1326Y621D03* 70 | X1126Y621D03* 71 | X1226Y219D03* 72 | X1026Y219D03* 73 | G54D14* 74 | X1526Y1321D03* 75 | X1526Y1121D03* 76 | X1526Y921D03* 77 | X1326Y1321D03* 78 | X1326Y1121D03* 79 | X1326Y921D03* 80 | X1526Y521D03* 81 | X1526Y421D03* 82 | X1526Y321D03* 83 | X1526Y1821D03* 84 | X1526Y1721D03* 85 | X1526Y1621D03* 86 | X426Y1921D03* 87 | X626Y1921D03* 88 | G54D15* 89 | X126Y121D03* 90 | X1526Y121D03* 91 | X126Y2021D03* 92 | X1526Y2021D03* 93 | G54D16* 94 | X226Y819D03* 95 | G54D17* 96 | X526Y1321D03* 97 | X326Y1621D03* 98 | X1326Y621D03* 99 | X1226Y219D03* 100 | G54D18* 101 | X1526Y1321D03* 102 | X1326Y1321D03* 103 | G54D19* 104 | X1226Y820D02* 105 | X1313Y646D01* 106 | D02* 107 | X1226Y1120D02* 108 | X1226Y820D01* 109 | D02* 110 | X1312Y1294D02* 111 | X1226Y1120D01* 112 | D02* 113 | X1404Y410D02* 114 | X1501Y339D01* 115 | D02* 116 | X1404Y962D02* 117 | X1404Y410D01* 118 | D02* 119 | X1339Y1094D02* 120 | X1404Y962D01* 121 | D02* 122 | X1126Y895D02* 123 | X1126Y649D01* 124 | D02* 125 | X926Y1549D02* 126 | X926Y1592D01* 127 | D02* 128 | X900Y1370D02* 129 | X921Y1493D01* 130 | D02* 131 | X849Y1337D02* 132 | X900Y1370D01* 133 | D02* 134 | X926Y1892D02* 135 | X926Y1649D01* 136 | D02* 137 | X227Y1521D02* 138 | X798Y1330D01* 139 | D02* 140 | X146Y1601D02* 141 | X227Y1521D01* 142 | D02* 143 | X799Y909D02* 144 | X756Y890D01* 145 | D02* 146 | X854Y221D02* 147 | X998Y219D01* 148 | D02* 149 | X756Y770D02* 150 | X802Y737D01* 151 | D02* 152 | X756Y890D02* 153 | X756Y770D01* 154 | D02* 155 | X900Y1058D02* 156 | X900Y962D01* 157 | D02* 158 | X847Y1102D02* 159 | X900Y1058D01* 160 | D02* 161 | X900Y962D02* 162 | X851Y935D01* 163 | D02* 164 | X446Y341D02* 165 | X805Y701D01* 166 | D02* 167 | X424Y1020D02* 168 | X505Y1101D01* 169 | D02* 170 | X424Y1020D02* 171 | X424Y1020D01* 172 | D02* 173 | X424Y920D02* 174 | X424Y1020D01* 175 | D02* 176 | X424Y1020D02* 177 | X424Y1020D01* 178 | D02* 179 | X497Y921D02* 180 | X424Y920D01* 181 | D02* 182 | X497Y1321D02* 183 | X424Y1321D01* 184 | D02* 185 | X324Y121D02* 186 | X625Y121D01* 187 | D02* 188 | X324Y222D02* 189 | X324Y121D01* 190 | D02* 191 | X324Y522D02* 192 | X324Y222D01* 193 | D02* 194 | X397Y521D02* 195 | X324Y522D01* 196 | D02* 197 | X424Y1120D02* 198 | X497Y1121D01* 199 | D02* 200 | X424Y1321D02* 201 | X424Y1120D01* 202 | D02* 203 | X612Y410D02* 204 | X825Y619D01* 205 | D02* 206 | X625Y121D02* 207 | X612Y410D01* 208 | D02* 209 | X941Y622D02* 210 | X960Y1058D01* 211 | D02* 212 | X1025Y1321D02* 213 | X1326Y1621D01* 214 | D02* 215 | X960Y1058D02* 216 | X1025Y1321D01* 217 | D02* 218 | X825Y619D02* 219 | X941Y622D01* 220 | D02* 221 | X1026Y995D02* 222 | X1026Y947D01* 223 | D02* 224 | X1526Y551D02* 225 | X1526Y891D01* 226 | D02* 227 | X1326Y1621D02* 228 | X1495Y1621D01* 229 | D02* 230 | X1020Y429D02* 231 | X1025Y895D01* 232 | D02* 233 | X252Y721D02* 234 | X497Y721D01* 235 | D02* 236 | X416Y1892D02* 237 | X335Y1648D01* 238 | D02* 239 | X1020Y1994D02* 240 | X1499Y1735D01* 241 | D02* 242 | X876Y1994D02* 243 | X1020Y1994D01* 244 | D02* 245 | X690Y1460D02* 246 | X876Y1994D01* 247 | G04 End of Copper1* 248 | M02* -------------------------------------------------------------------------------- /docs/headphone-amp/original/gerber/Houston Headphone amp 3.gts: -------------------------------------------------------------------------------- 1 | G04 MADE WITH FRITZING* 2 | G04 WWW.FRITZING.ORG* 3 | G04 DOUBLE SIDED* 4 | G04 HOLES PLATED* 5 | G04 CONTOUR ON CENTER OF CONTOUR VECTOR* 6 | %ASAXBY*% 7 | %FSLAX23Y23*% 8 | %MOIN*% 9 | %OFA0B0*% 10 | %SFA1.0B1.0*% 11 | %ADD10C,0.072992*% 12 | %ADD11C,0.049370*% 13 | %ADD12C,0.085000*% 14 | %ADD13C,0.080000*% 15 | %ADD14C,0.088000*% 16 | %ADD15C,0.167480*% 17 | %ADD16R,0.072992X0.072992*% 18 | %ADD17R,0.085000X0.085000*% 19 | %ADD18R,0.088000X0.088000*% 20 | %LNMASK1*% 21 | G90* 22 | G70* 23 | G54D10* 24 | X226Y819D03* 25 | X226Y721D03* 26 | G54D11* 27 | X1020Y410D03* 28 | X684Y1442D03* 29 | G54D12* 30 | X526Y1321D03* 31 | X826Y1321D03* 32 | X526Y1221D03* 33 | X826Y1221D03* 34 | X526Y1121D03* 35 | X826Y1121D03* 36 | X526Y1021D03* 37 | X826Y1021D03* 38 | X526Y921D03* 39 | X826Y921D03* 40 | X526Y821D03* 41 | X826Y821D03* 42 | X526Y721D03* 43 | X826Y721D03* 44 | X926Y1921D03* 45 | X1326Y1921D03* 46 | X1126Y1621D03* 47 | X1126Y1221D03* 48 | X526Y1621D03* 49 | X926Y1621D03* 50 | X426Y321D03* 51 | X826Y321D03* 52 | X526Y1521D03* 53 | X926Y1521D03* 54 | X426Y521D03* 55 | X826Y521D03* 56 | X426Y221D03* 57 | X826Y221D03* 58 | X426Y421D03* 59 | X826Y421D03* 60 | G54D13* 61 | X1026Y921D03* 62 | X1126Y921D03* 63 | X1026Y1021D03* 64 | X1126Y1021D03* 65 | G54D12* 66 | X326Y1621D03* 67 | X126Y1621D03* 68 | X1326Y621D03* 69 | X1126Y621D03* 70 | X1226Y219D03* 71 | X1026Y219D03* 72 | G54D14* 73 | X1526Y1321D03* 74 | X1526Y1121D03* 75 | X1526Y921D03* 76 | X1326Y1321D03* 77 | X1326Y1121D03* 78 | X1326Y921D03* 79 | X1526Y521D03* 80 | X1526Y421D03* 81 | X1526Y321D03* 82 | X1526Y1821D03* 83 | X1526Y1721D03* 84 | X1526Y1621D03* 85 | X426Y1921D03* 86 | X626Y1921D03* 87 | G54D15* 88 | X126Y121D03* 89 | X1526Y121D03* 90 | X126Y2021D03* 91 | X1526Y2021D03* 92 | G54D16* 93 | X226Y819D03* 94 | G54D17* 95 | X526Y1321D03* 96 | X326Y1621D03* 97 | X1326Y621D03* 98 | X1226Y219D03* 99 | G54D18* 100 | X1526Y1321D03* 101 | X1326Y1321D03* 102 | G04 End of Mask1* 103 | M02* -------------------------------------------------------------------------------- /docs/headphone-amp/original/gerber/Houston Headphone amp 3.txt: -------------------------------------------------------------------------------- 1 | ; NON-PLATED HOLES START AT T1 2 | ; THROUGH (PLATED) HOLES START AT T100 3 | M48 4 | INCH 5 | T100C0.038000 6 | T101C0.118110 7 | T102C0.015748 8 | T103C0.031497 9 | T104C0.030000 10 | T105C0.035000 11 | % 12 | T100 13 | X015255Y018207 14 | X006255Y019207 15 | X015255Y009207 16 | X015255Y003207 17 | X015255Y013207 18 | X015255Y004207 19 | X015255Y005207 20 | X013255Y011207 21 | X015255Y016207 22 | X015255Y017207 23 | X013255Y009207 24 | X015255Y011207 25 | X013255Y013207 26 | X004255Y019207 27 | T101 28 | X015255Y001207 29 | X015255Y020207 30 | X001255Y001207 31 | X001255Y020207 32 | T102 33 | X006840Y014419 34 | X010200Y004099 35 | T103 36 | X002255Y008191 37 | X002255Y007207 38 | T104 39 | X010255Y010207 40 | X011257Y009207 41 | X011257Y010207 42 | X010255Y009207 43 | T105 44 | X008255Y004207 45 | X005255Y009207 46 | X011255Y006207 47 | X013255Y006207 48 | X013255Y019207 49 | X008255Y009207 50 | X004255Y002207 51 | X005255Y010207 52 | X008255Y010207 53 | X009255Y015207 54 | X005255Y015207 55 | X011255Y012207 56 | X008255Y002207 57 | X005255Y007207 58 | X008255Y007207 59 | X010263Y002191 60 | X012263Y002191 61 | X004255Y005207 62 | X005255Y013207 63 | X008255Y013207 64 | X008255Y005207 65 | X004255Y003207 66 | X005255Y011207 67 | X008255Y011207 68 | X001255Y016207 69 | X003255Y016207 70 | X009255Y016207 71 | X005255Y016207 72 | X008255Y003207 73 | X005255Y008207 74 | X008255Y008207 75 | X009255Y019207 76 | X011255Y016207 77 | X004255Y004207 78 | X005255Y012207 79 | X008255Y012207 80 | T00 81 | M30 82 | -------------------------------------------------------------------------------- /docs/houston_tracker_2-30_memo.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utz82/HoustonTracker2/1915cea4016d5e55dcb5f7f782b2822d642e216c/docs/houston_tracker_2-30_memo.pdf -------------------------------------------------------------------------------- /docs/line-mod-3.5mm/image0.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utz82/HoustonTracker2/1915cea4016d5e55dcb5f7f782b2822d642e216c/docs/line-mod-3.5mm/image0.jpeg -------------------------------------------------------------------------------- /docs/line-mod-3.5mm/image1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utz82/HoustonTracker2/1915cea4016d5e55dcb5f7f782b2822d642e216c/docs/line-mod-3.5mm/image1.jpeg -------------------------------------------------------------------------------- /docs/line-mod-3.5mm/image2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/utz82/HoustonTracker2/1915cea4016d5e55dcb5f7f782b2822d642e216c/docs/line-mod-3.5mm/image2.jpeg -------------------------------------------------------------------------------- /font.asm: -------------------------------------------------------------------------------- 1 | ;Compressed bitmaps for the font used by HT2. 2 | ; 3 | ; Five nibbles (2.5 bytes) per character 4 | ; Will be unpacked to 5 bytes per character 5 | 6 | ; Currently 0x00 to 0x1a => 27 different characters 7 | ; - Compressed space in RAM = 27*2.5 = 67.5 => 68 bytes = 0x44 8 | ; - Uncompressed space in RAM = 27*5 = 135 bytes = 0x87 9 | ; Then right-shifted variants of all but the ones that doesn't need it (G, M, STOP, PLAY) 10 | ; - Uncompressed space in RAM = (27-4)*5 = 115 bytes = 0x73 11 | ; Total needed space in RAM = 135+115=250 bytes, fits in one page. 12 | 13 | CHAR_0 equ #00 14 | CHAR_1 equ #01 15 | CHAR_2 equ #02 16 | CHAR_3 equ #03 17 | CHAR_4 equ #04 18 | CHAR_5 equ #05 19 | CHAR_6 equ #06 20 | CHAR_7 equ #07 21 | CHAR_8 equ #08 22 | CHAR_9 equ #09 23 | CHAR_A equ #0a 24 | CHAR_B equ #0b 25 | CHAR_C equ #0c 26 | CHAR_D equ #0d 27 | CHAR_E equ #0e 28 | CHAR_F equ #0f 29 | CHAR_L equ #10 30 | CHAR_N equ #11 31 | CHAR_P equ #12 32 | CHAR_O equ CHAR_0 33 | CHAR_S equ #13 34 | CHAR_T equ #14 35 | CHAR_SHARP equ #15 36 | CHAR_DASH equ #16 37 | CHAR_G equ #17 38 | CHAR_M equ #18 39 | CHAR_STOP equ #19 40 | CHAR_PLAY equ #1a 41 | 42 | charNumTotal equ CHAR_PLAY-CHAR_0+1 ; Number of characters, total 43 | charNumShifted equ CHAR_DASH-CHAR_0+1 ; Number of characters to be available as both left and right shifted 44 | 45 | IF (charNumTotal+charNumShifted)*5 > 256 ; Make sure we don't need more than one page of uncompressed font 46 | .error Uncompressed font will cross page boundary 47 | ENDIF 48 | 49 | cmprFontStart 50 | db %01001010 ;0 51 | db %10101010 52 | db %01000100 ;....|1 53 | 54 | db %11000100 55 | db %01001110 56 | 57 | db %11000010 ;2 58 | db %01001000 59 | db %11101100 ;....|3 60 | 61 | db %00100100 62 | db %00101100 63 | 64 | db %10001010 ;4 65 | db %11100010 66 | db %00101100 ;....|5 67 | 68 | db %10001100 69 | db %00101100 70 | 71 | db %01001000 ;6 72 | db %11001010 73 | db %01001110 ;....|7 74 | 75 | db %00100100 76 | db %01000100 77 | 78 | db %01001010 ;8 79 | db %01001010 80 | db %01000100 ;....|9 81 | 82 | db %10100110 83 | db %00100100 84 | 85 | db %01101010 ;A 86 | db %11101010 87 | db %10101100 ;....|B 88 | 89 | db %10101100 90 | db %10101100 91 | 92 | db %01101000 ;C 93 | db %10001000 94 | db %01101100 ;....|D 95 | 96 | db %10101010 97 | db %10101100 98 | 99 | db %11101000 ;E 100 | db %11001000 101 | db %11101110 ;....|F 102 | 103 | db %10001100 104 | db %10001000 105 | 106 | db %10001000 ;10 - L 107 | db %10001000 108 | db %11101100 ;....|N 109 | 110 | db %10101010 111 | db %10101010 112 | 113 | db %11001010 ;12 - P 114 | db %11001000 115 | db %10000110 ;....|S 116 | 117 | db %10000100 118 | db %00101100 119 | 120 | db %11100100 ;14 - T 121 | db %01000100 122 | db %01001010 ;....|# 123 | 124 | db %11101010 125 | db %11101010 126 | 127 | db %00000000 ;16 - - 128 | db %11100000 129 | db %00000110 ;....|G (17) 130 | 131 | db %10001010 132 | db %10101110 133 | 134 | db %10101110 ;18 - M 135 | db %11101010 136 | db %10100000 ;....|STOP (19) 137 | 138 | db %11101110 139 | db %11100000 140 | 141 | db %10001100 ;PLAY (1a) 142 | db %11101100 143 | db %10000000 ;....| 144 | cmprFontSize equ $-cmprFontStart 145 | -------------------------------------------------------------------------------- /gfx.asm: -------------------------------------------------------------------------------- 1 | ;******************************************************************************* 2 | ;GRAPHICS AND PRINTING ROUTINES 3 | ;******************************************************************************* 4 | ;******************************************************************************* 5 | ;error handling 6 | ;******************************************************************************* 7 | 8 | errorHand0 ;clear StateSelect (when entering from LOAD/SAVE) 9 | ex af,af' 10 | ld a,#16 11 | ld (StateSelect),a 12 | ex af,af' 13 | 14 | errorHand ;error handler 15 | ;IN: A - error code 16 | ld d,CHAR_E 17 | ld e,a 18 | printMsg ;print a message to the message area 19 | ;IN: DE - message 20 | push de 21 | 22 | ex af,af' ;';TODO: preserving A for what? 23 | setXYat #29, #b2 24 | ex af,af' 25 | 26 | pop de 27 | 28 | jp printDE 29 | 30 | 31 | ;******************************************************************************* 32 | printMute12 ;print Mute state ch1/2 33 | setXYat #2a, #88 34 | 35 | ld de,#0102 36 | ld a,(MuteState) 37 | rra 38 | jr nc,_skip 39 | ld d,CHAR_DASH 40 | _skip 41 | rra 42 | jr nc,_skip2 43 | ld e,CHAR_DASH 44 | _skip2 45 | jp printDE 46 | 47 | 48 | printMute3D ;print Mute state ch3/4 49 | setXYat #2b, #88 50 | 51 | ld de,#030D 52 | ld a,(MuteState) 53 | rla 54 | jr nc,_skip 55 | ld e,CHAR_DASH 56 | _skip 57 | rla 58 | jr nc,_skip2 59 | ld d,CHAR_DASH 60 | _skip2 61 | jp printDE 62 | 63 | ;************************************************************************************ 64 | initSeqCsr 65 | ld a,(OldCsrPos) ;reset cursor pos 66 | ld (CsrPos),a 67 | 68 | printCsr ;print the cursor 69 | ld hl,CsrTab ;load pointer to CsrPos LUT 70 | 71 | csrTypeSwap equ $+1 72 | ld c,#0f ;cursor bitmask 73 | ld a,(CsrPos) 74 | add a,a ;A=A*2 75 | add a,l 76 | ld l,a 77 | ld a,(hl) 78 | or a 79 | jp p,_skip ;if bit 7 is set 80 | ld c,#f0 ;change bitmask to #f0 81 | and %01111111 ;clear bit 7 82 | _skip 83 | ld d,a 84 | inc l 85 | ld e,(hl) 86 | call setXY 87 | 88 | IF MODEL = TI82 89 | ld a,(hl) ;waste some time 90 | ld a,(hl) 91 | ELSE 92 | call lcdWait3 93 | ENDIF 94 | ld a,c 95 | out (lcd_data),a 96 | ret 97 | 98 | printCsr2 ;alternative table pointer for FX screen 99 | ld hl,CsrTab2 100 | jr printCsr+3 101 | 102 | delCsr2 ;alternative table pointer for FX screen 103 | ld hl,CsrTab2 104 | jr delCsr+3 105 | 106 | delCsr ;delete the cursor 107 | ld hl,CsrTab ;load pointer to CsrPos LUT 108 | ld a,(CsrPos) 109 | add a,a ;A=A*2 110 | add a,l 111 | ld l,a 112 | ld a,(hl) 113 | and %01111111 ;clear bit 7 114 | ld d,a 115 | inc l 116 | ld e,(hl) 117 | call setXY 118 | 119 | IF MODEL = TI82 120 | ld a,(hl) 121 | ld a,(hl) 122 | ELSE 123 | call lcdWait3 124 | ENDIF 125 | xor a 126 | out (lcd_data),a 127 | ret 128 | 129 | ;******************************************************************************* 130 | printFxScr ;print an FX pattern screen 131 | 132 | call clrMsgArea ;clear message area 133 | 134 | ld a,LOW(kjumptab)+16 ;set dirkey jump table pointer offset 135 | ld (kdirswitch),a 136 | 137 | ld a,(CsrPos) ;preserve cursor pos on seq.scr 138 | ld (OldCsrPos),a 139 | 140 | ld a,2 ;set current screen type 141 | ld (CScrType),a 142 | 143 | call printSingleLN 144 | 145 | _header ;printing ptn#/curr. octave info 146 | setXYat #21, #82 147 | printTwoChars CHAR_P, CHAR_T ;PT(N) 148 | 149 | setXYat #23, #82 150 | 151 | call getSeqOffset ;find pattern# 152 | 153 | ld a,(CPtn) ;load current ptn# 154 | cp #40 ;if it's invalid (> #3f) 155 | jp nc,printSeqScr ;default to sequence screen 156 | 157 | printFxScrNoInit ;init point when cycling through patterns 158 | 159 | call printChars ;print ptn# 160 | 161 | setXYat #21, #8e 162 | 163 | ld a,(CPtn) 164 | ld hl,fxptntab 165 | call findCurrFxPtn ;get the pattern pointer 166 | 167 | push de ;preserve pointer for printing fx params later 168 | 169 | ex de,hl 170 | 171 | call printFXP 172 | 173 | setXYat #25, #8e 174 | 175 | call printFXP 176 | 177 | setXYat #22, #8e 178 | 179 | pop hl 180 | inc hl 181 | 182 | call printFXP 183 | 184 | setXYat #26, #8e 185 | 186 | call printFXP 187 | 188 | xor a ;reset cursor pos 189 | ld (CsrPos),a 190 | call printCsr2 ;initialize cursor 191 | 192 | call waitForKeyRelease 193 | jp keyhand 194 | 195 | printFXP ;print FX params 196 | ld b,8 197 | _lp 198 | ld a,(hl) 199 | inc hl 200 | inc hl 201 | push hl 202 | push bc 203 | call printCharsNoFF 204 | pop bc 205 | pop hl 206 | djnz _lp 207 | 208 | ret 209 | 210 | ;******************************************************************************* 211 | 212 | 213 | 214 | printPtnScr ;print a pattern screen 215 | 216 | call clrMsgArea ;clear message area 217 | 218 | ld a,LOW(kjumptab)+8 ;set dirkey jump table pointer offset 219 | ld (kdirswitch),a 220 | 221 | ld a,1 ;set current screen type 222 | ld (CScrType),a 223 | 224 | ld a,(CsrPos) 225 | ld (OldCsrPos),a 226 | 227 | call printSingleLN 228 | 229 | _header ;printing ptn#/curr. octave info 230 | setXYat #21, #82 231 | printTwoChars CHAR_P, CHAR_T ;PT(N) 232 | printTwoChars CHAR_O, CHAR_C ;OC(T) 233 | 234 | setXYat #23, #82 235 | 236 | call getSeqOffset 237 | 238 | ld a,(CPtn) ;current ptn# 239 | cp #80 ;if pattern# > #7f 240 | jp nc,printSeqScr ;default to sequence screen 241 | 242 | printPtnScrNoInit ;init point when cycling through patterns 243 | 244 | call printChars 245 | 246 | ld a,(COct) ;current octave 247 | call printCharL 248 | 249 | printPtnScrBasic ;init point when not reprinting ptn nr, octave etc. 250 | setXYat #21, #8e 251 | 252 | call findCurrPtn 253 | 254 | push de ;preserve pointer for printing octave #s later 255 | 256 | call printNoteNames 257 | ex de,hl 258 | setXYat #25, #8e 259 | 260 | ex de,hl 261 | call printNoteNames 262 | 263 | setXYat #22, #8e 264 | 265 | pop de ;retrieve pattern pointer 266 | 267 | call printOctaves 268 | 269 | push de 270 | setXYat #26, #8e 271 | 272 | pop de 273 | call printOctaves 274 | 275 | ld a,#50 ;init cursor pos 276 | ld (CsrPos),a 277 | 278 | ld a,#ff ;init cursor type 279 | ld (csrTypeSwap),a 280 | 281 | call printCsr 282 | 283 | call waitForKeyRelease 284 | jp keyhand 285 | 286 | 287 | printOctaves 288 | ld b,8 289 | _lp 290 | ld a,(de) ;read note byte 291 | inc de ;point to next byte 292 | push de ;preserve pattern pointer 293 | push bc ;preserve counter 294 | or a 295 | jr nz,_skip2 ;if note val = 0 296 | ld a,CHAR_DASH ;print a dash 297 | jr _skip3 298 | _skip2 299 | call divNoteVal ;octave val returned in B 300 | 301 | ld a,b ;get it into A 302 | _skip3 303 | ex af,af' 304 | call clearPrintBuf 305 | ex af,af' 306 | call printCharLNC ;and print it 307 | 308 | pop bc 309 | pop de 310 | djnz _lp 311 | ret 312 | 313 | 314 | 315 | 316 | printNoteNames 317 | ld b,8 318 | _lp 319 | ld a,(de) ;read note byte 320 | inc de 321 | push de 322 | push bc 323 | or a 324 | jr nz,_skip2 ;if note val = 0 325 | ld d,CHAR_DASH ;load dashes into DE 326 | ld e,d 327 | jr _skip3 328 | _skip2 329 | call divNoteVal ;note val returned in C 330 | 331 | ld a,c ;find note name 332 | ld hl,notenames ;point to note name LUT 333 | add a,a ;A=A*2 334 | ld e,a 335 | ld d,0 336 | add hl,de ;add offset to LUT pointer 337 | 338 | ld d,(hl) ;get string into DE 339 | inc hl 340 | ld e,(hl) 341 | 342 | _skip3 343 | call printDE ;and print it 344 | 345 | pop bc 346 | pop de 347 | djnz _lp 348 | ret 349 | 350 | 351 | 352 | 353 | printSingleLN ;print single digit line numbers 354 | setXYat #20, #8e 355 | 356 | xor a ;starting with line 0 357 | ld b,8 358 | 359 | call printSingleLP ;print the first column 360 | 361 | setXYat #24, #8e 362 | 363 | ld a,8 ;starting with 8, print 2nd column 364 | ld b,a 365 | call printSingleLP 366 | 367 | ret 368 | 369 | printSingleLP ;print loop for printing single digit line #s 370 | push af 371 | push bc 372 | call printCharL 373 | pop bc 374 | pop af 375 | inc a 376 | djnz printSingleLP 377 | ret 378 | 379 | ;************************************************************************************ 380 | printSeqScr ;print the sequence (main) screen 381 | ;call clrMsgArea ;clear message area 382 | 383 | ld a,LOW(kjumptab) ;reset dirkey jump table pointer offset 384 | ld (kdirswitch),a 385 | 386 | xor a 387 | ld (CScrType),a ;set current screen type 388 | ld (InputType),a ;reset input type 389 | 390 | ld a,#0f ;init cursor type 391 | ld (csrTypeSwap),a 392 | 393 | printSeqScr0 394 | printLineNumbers ;print line numbers on main screen 395 | setXYat #20, #82 396 | 397 | ld b,10 ;10 lines to print 398 | ld a,(FirstLineMS) ;load first line number 399 | 400 | _plnlp 401 | push af 402 | push bc 403 | call printCharsNoFF 404 | pop bc 405 | pop af 406 | inc a 407 | djnz _plnlp 408 | 409 | printPtnSequence 410 | setXYat #21, #82 ;ch1 411 | 412 | ld hl,ptns ;point HL to start of ptn sequence 413 | ld a,(FirstLineMS) ;get first row to be printed 414 | ld e,a ;load into DE 415 | ld d,0 416 | add hl,de ;first row * 4 = offset in ptn sequence 417 | add hl,de 418 | add hl,de 419 | add hl,de 420 | 421 | ld c,10 ;printing 10 rows for each column 422 | call printSeqColR ;print upper nibbles 423 | setXYat #22, #82 424 | call printSeqColL ;print lower nibbles 425 | 426 | setXYat #23, #82 ;ch2 427 | 428 | inc hl ;increment to point to next channel 429 | push hl ;preserve seq. pointer (printSeqCol doesn't do this for speed reasons) 430 | call printSeqCol 431 | 432 | setXYat #24, #82 ;ch3 433 | pop hl 434 | 435 | inc hl 436 | call printSeqColR 437 | setXYat #25, #82 438 | call printSeqColL 439 | 440 | setXYat #26, #82 ;fx-ch 441 | 442 | inc hl 443 | call printSeqCol 444 | 445 | ld a,(OldCsrPos) 446 | ld (CsrPos),a 447 | 448 | ret 449 | 450 | ;************************************************************************************ 451 | printSeqColR ;print one right half-column of pattern sequence 452 | push hl ;preserve seq. pointer 453 | ld b,c ;printing 10 rows for each column 454 | _ppslp 455 | push hl ;preserve sequence pointer 456 | push bc ;preserve counter 457 | ld a,(hl) ;load byte to print 458 | call printCharR ;print upper nibble, right-aligned 459 | pop bc ;retrieve counter 460 | pop hl ;retrieve seq. pointer 461 | ld de,4 ;increment seq. pointer (by 4, because each row of the sequence is 4 bytes long) 462 | add hl,de 463 | djnz _ppslp ;loop until 10 rows have been printed 464 | pop hl ;retrieve seq. pointer 465 | ret 466 | 467 | 468 | printSeqColL ;print one left half-column of pattern sequence 469 | push hl 470 | ld b,c 471 | _ppslp 472 | push hl 473 | push bc 474 | ld a,(hl) 475 | call printCharL 476 | pop bc 477 | pop hl 478 | ld de,4 479 | add hl,de 480 | djnz _ppslp 481 | pop hl 482 | ret 483 | 484 | 485 | printSeqCol ;print one full column of pattern sequence 486 | ld b,c 487 | _ppslp 488 | push hl 489 | push bc 490 | ld a,(hl) 491 | call printChars 492 | pop bc 493 | pop hl 494 | ld de,4 495 | add hl,de 496 | djnz _ppslp 497 | ret 498 | 499 | ;************************************************************************************ 500 | printCharR 501 | ex af,af' ;preserve byte to be printed 502 | call clearPrintBuf ;clear print buffer 503 | ex af,af' ;retrieve byte to be printed 504 | call hex2charU ;convert upper nibble 505 | ld c,1 ;init registers for setting up the print buffer (c=number of digits to print, b'=shifted char offset) 506 | exx 507 | ld b,charNumTotal*5 ;point to right-shifted start 508 | call setupPB1char ;setup print buffer 509 | jr printBuf ;and finally print what's in the buffer 510 | 511 | 512 | printCharL 513 | ex af,af' 514 | call clearPrintBuf 515 | ex af,af' 516 | call hex2charL 517 | printCharLNC 518 | ld c,1 519 | exx 520 | ld b,0 521 | call setupPB1char 522 | jr printBuf 523 | 524 | 525 | 526 | printCharsNoFF 527 | call hex2charNoFF 528 | jr printCharsNoConvert 529 | 530 | printChars ;print the 2 characters in (CharString) 531 | call hex2char ;convert to chars 532 | 533 | printCharsNoConvert ;print (CharString) without converting ASCII first 534 | ld de,(CharString) ;load chars into DE 535 | 536 | printDE ;printing with custom value in DE 537 | call setupPrintBuf ;convert to bitmap 538 | 539 | printBuf 540 | ld hl,PrintBuf ;print a pair of characters 541 | ld b,6 542 | jp drawlp2 543 | 544 | ;******************************************************************************* 545 | printPlayModeIndicator 546 | setXYat #29, #88 547 | 548 | ld a,(PlayerFlag) 549 | or a 550 | ld d,CHAR_STOP ; ... 551 | jr z,_playerStopped 552 | 553 | ld d,CHAR_PLAY ;... or 554 | 555 | _playerStopped 556 | 557 | ld a,(SynthMode) 558 | or a 559 | jr z,_noSynthMode 560 | 561 | ld e,CHAR_S 562 | jp printDE 563 | 564 | _noSynthMode 565 | call clearPrintBuf 566 | ld a,d 567 | jp printCharLNC 568 | 569 | ;******************************************************************************* 570 | printSaveSlotIndicator ;enter with A = slot number 571 | ex af,af' 572 | setXYat #2b, #ac 573 | 574 | ex af,af' 575 | ld d,CHAR_S ;"S" 576 | ld e,a 577 | jp printDE 578 | 579 | ;************************************************************************************ 580 | clearPrintBuf ;clear the print buffer in (ops) 581 | xor a 582 | ld hl,ops 583 | ld b,5 584 | cpblp 585 | ld (hl),a 586 | inc l 587 | djnz cpblp 588 | ret 589 | 590 | ;************************************************************************************ 591 | setupPrintBuf ;set up print buffer with 5-byte bitmap (2 chars) 592 | ;INPUT: left char in d, right char in e 593 | 594 | call clearPrintBuf ;clear the print buffer 595 | 596 | ld a,d ;load first (left) char 597 | ld c,2 ;printing 2 characters 598 | exx 599 | ld b,0 600 | 601 | setupPB1char ;init point for printing 1 char 602 | ;char in A, B' = 0 (left) or offset to right, C=1, print buffer must be cleared manually 603 | 604 | ld d,HIGH(FontLUT) ;point to font bitmaps 605 | _spblp 606 | ld hl,ops ;print buffer resides in (ops) 607 | 608 | ld c,a ;multiply character byte * 5 609 | add a,a 610 | add a,a 611 | add a,c 612 | add a,b ;and add right side offset as required 613 | ld e,a 614 | ld b,5 615 | _getbitslp ;get 5 byte-length bitmaps 616 | ld a,(de) 617 | or (hl) ;and or them into the print buffer 618 | ld (hl),a 619 | inc e 620 | inc l ;inc hl 621 | djnz _getbitslp 622 | 623 | exx 624 | dec c ;check if all chars have been set up 625 | ret z ;and return if yes 626 | 627 | ld a,e ;otherwise, get second char 628 | exx 629 | ld b,charNumTotal*5 ;prep b with offset for right-shifted chars 630 | jr nz,_spblp ;JR NZ??? It's always NZ at this point. 631 | 632 | ;************************************************************************************ 633 | clrS ;clear main screen area 634 | ld d,#1f ;select horiz. pos 635 | ld c,7 ;clearing 7 columns 636 | _clrlp 637 | inc d 638 | ld e,#82 639 | call setXY 640 | 641 | xor a 642 | ld b,#3c ;clearing #3b rows 643 | call drawLoop 644 | 645 | dec c 646 | jr nz,_clrlp 647 | ret 648 | 649 | 650 | ;************************************************************************************ 651 | drawLoop ;simple draw loop (used for screen initialization) 652 | out (lcd_data),a 653 | call lcdWait3 654 | djnz drawLoop 655 | ret 656 | 657 | drawlp2 ;little more complex draw loop 658 | ld a,(hl) 659 | inc hl 660 | out (lcd_data),a 661 | IF MODEL = TI82 662 | push hl ;waste some time 663 | pop hl 664 | ELSE 665 | call lcdWait3 666 | ENDIF 667 | djnz drawlp2 668 | ret 669 | 670 | ;************************************************************************************ 671 | lcdWait2 ;waste some time till LCD controller can receive next command 672 | jr lcdWait3 ;12t 673 | lcdWait3 674 | 675 | IF MODEL != TI82 ;lcdWait for slow display drivers 676 | ex (sp),hl 677 | ex (sp),hl 678 | ex (sp),hl 679 | ex (sp),hl 680 | ex (sp),hl 681 | ex (sp),hl 682 | ex (sp),hl 683 | ex (sp),hl ;152 684 | ENDIF 685 | ret 686 | 687 | ;************************************************************************************ 688 | setXY ;set print position on screen 689 | ;input: D=horiz.pos, E=vert.pos | out: A destroyed 690 | ld a,d ;set horizontal pos 691 | out (lcd_crt),a 692 | call lcdWait2 693 | 694 | ld a,e ;set vertical pos 695 | out (lcd_crt),a 696 | 697 | setXYmod equ $+1 698 | jr lcdWait2 ;exit via lcdWait2 - SELF-MODIFYING: swapped with a jr to lcdWait3 after initSCR 699 | 700 | -------------------------------------------------------------------------------- /include/scratchpad.inc: -------------------------------------------------------------------------------- 1 | ;******************************************************************************* 2 | ;scratch pad memory index and other equates 3 | ;******************************************************************************* 4 | 5 | CharString equ apd_buf+#00 ;2 2 character codes for printing 6 | FirstLineMS equ apd_buf+#02 ;1 first line of sng sequence to be displayed on main screen 7 | CPS equ apd_buf+#03 ;1 start of copy block 8 | CPE equ apd_buf+#04 ;1 end of copy block 9 | 10 | SourcePtn equ apd_buf+#05 ;1 number of the source pattern (for copying to another pattern) 11 | 12 | 13 | CScrType equ apd_buf+#06 ;1 current type of screen (0=main, 1=ptn, 2=fxptn) 14 | AlphaFlag equ apd_buf+#07 ;1 #a0 if Alpha has been pressed, else 0 15 | 16 | PlayerFlag equ apd_buf+#08 ;1 0 if player is stopped, 1 if running 17 | 18 | COct equ apd_buf+#09 ;1 current octave 19 | CPtn equ apd_buf+#0a ;1 current pattern 20 | 21 | CSRow equ apd_buf+#0b ;1 current row in ptn sequence 22 | CSCol equ apd_buf+#0c ;1 current column in ptn sequence 23 | 24 | CPRow equ apd_buf+#0d ;1 current row in pattern 25 | CPCol equ apd_buf+#0e ;1 current column in pattern 26 | 27 | CsrPos equ apd_buf+#0f ;1 cursor position 28 | OldCsrPos equ apd_buf+#10 ;1 temp backup cursor position on main screen 29 | OldCsrPos2 equ apd_buf+#11 ;1 temp backup current cursor pos (for handling vars) 30 | 31 | CurVal equ apd_buf+#12 ;1 current cursor bitmap value (#0f, #f0, or #ff) 32 | 33 | MuteState equ apd_buf+#13 ;1 mute state of channels (bit 7 = drums, bit 6 = ch3, bit 1 = ch2, bit 0 = ch1) 34 | 35 | InputType equ apd_buf+#14 ;1 input type (0=regular, 1=single digit, 2=double digit, 4=word, 6=low nibble) 36 | 37 | StateSelect equ apd_buf+#15 ;1 number of the currently selected save slot 38 | 39 | AutoInc equ apd_buf+#16 ;1 auto inc mode (1 = off, 0 = on) 40 | 41 | RowPlay equ apd_buf+#17 ;1 RowPlay mode (0 = off, #ff = on) 42 | 43 | LastKey equ apd_buf+#18 ;1 #a0 if last key set ALPHA mode on, else 0 44 | 45 | reptpos equ apd_buf+#19 ;1 number of remaining rows in pattern during playback 46 | 47 | SynthMode equ apd_buf+#20 ;1 Synth mode (0 = off, #ff = on). 48 | 49 | ;ReInit equ apd_buf+#1a ;1 flag for reinitialization 50 | 51 | PrintBuf equ ops ;6 print bitmap buffer 52 | 53 | FontLUT equ 256*((HIGH(apd_buf))+1) ;font LUT 54 | 55 | NoteTab equ 256*((HIGH(apd_buf))+2) ;note LUT 56 | 57 | CsrTab equ 256*((HIGH(graph_mem))+1) ;cursor position LUT 58 | 59 | IF MODEL = TI83 ;fx pattern screen cursor position LUT 60 | CsrTab2 equ graph_mem ;generated on the lowest page of graph_mem on TI83 61 | ENDIF 62 | IF MODEL = TI82 || MODEL = TI8P ;generated on the lowest page of apd_buf on TI82 63 | CsrTab2 equ #80+(256*(HIGH(apd_buf))) 64 | ENDIF 65 | IF MODEL = TI8X || MODEL = TI8XS 66 | CsrTab2 equ 256*((HIGH(text_mem2))+1) ;generated on the second page of statram on TI83P 67 | ENDIF 68 | 69 | ptntab equ 256*((HIGH(graph_mem))+2) ;pattern table 70 | 71 | fxptntab equ text_mem2 72 | 73 | 74 | ;************************************************************************************ 75 | ;HW Constants 76 | ;************************************************************************************ 77 | 78 | ; Used by kbd port 79 | KBD_GROUP_DIRPAD equ #fe 80 | KBD_GROUP_ENTER equ #fd 81 | KBD_GROUP_MINUS equ #fb 82 | KBD_GROUP_DOT equ #f7 83 | KBD_GROUP_ZERO equ #ef 84 | KBD_GROUP_ALPHA equ #df 85 | KBD_GROUP_GRAPH equ #bf 86 | 87 | ;************************************************************************************ 88 | ;Macros 89 | ;************************************************************************************ 90 | 91 | 92 | ; Set printing cursor at X, Y. DE is destroyed 93 | MACRO setXYat, X, Y 94 | ld de,256*X+Y 95 | call setXY 96 | ENDM 97 | 98 | ; Prepares DE with a two-byte string. DE is destroyed 99 | MACRO ld_de_TwoChars, firstChar, secondChar 100 | ld de,256*firstChar+secondChar 101 | ENDM 102 | 103 | ; Print a two-byte string. DE is destroyed 104 | MACRO printTwoChars, firstChar, secondChar 105 | ld_de_TwoChars firstChar, secondChar 106 | call printDE 107 | ENDM 108 | -------------------------------------------------------------------------------- /include/ti82.inc: -------------------------------------------------------------------------------- 1 | ;********************************************************************************** 2 | ;include file for TI-82/CrASH 1.6 3 | ;********************************************************************************** 4 | 5 | progstart equ #9104 ;all CrASH programs start here 6 | 7 | org progstart 8 | 9 | ;********************************************************************************** 10 | ;ports 11 | 12 | link equ #00 ;link port 13 | kbd equ #01 ;keyboard port 14 | rom equ #02 ;ROM page select port 15 | kon equ #03 ;ON key port 16 | lcd_crt equ #10 ;lcd control port 17 | lcd_data equ #11 ;ldc data port 18 | 19 | ;********************************************************************************** 20 | ;link port states 21 | 22 | lp_on equ #fc ;link port off 23 | lp_off equ #c0 ;link port on 24 | lp_l equ #d4 ;link port left on 25 | lp_r equ #e8 ;link port right on 26 | lp_sw equ #3c ;toggle link port state 27 | lp_swl equ #28 ;toggle link port state left 28 | lp_swr equ #14 ;toggle link port state right 29 | ;lp_msk equ #fcfc ;link port mask 30 | lp_msk equ #c0c0 31 | lp_smsk equ #d4e8 ;link port stereo mask 32 | 33 | ;********************************************************************************** 34 | ;saferam addresses 35 | 36 | graph_mem equ #88b8 ;768 bytes 37 | apd_buf equ #8228 ;768 bytes 38 | text_mem equ #808f ;128 bytes 39 | text_mem2 equ #8bdf ;128 bytes 40 | ops equ #8028 ;66 bytes 41 | 42 | mem_end equ #fcb3 ;user memory end (excl. safety margin) 43 | 44 | ;********************************************************************************** 45 | ;rom_call macro 46 | 47 | macro rom_call,addr 48 | call #8d74 49 | dw addr 50 | endm 51 | 52 | macro key_delay 53 | nop 54 | nop 55 | endm 56 | 57 | 58 | ;********************************************************************************** 59 | ;rom calls 60 | 61 | clearlcd equ #389a ;clear LCD, but not text or graphics memory 62 | cleartext_f equ #37A4 ;clear text_mem 63 | 64 | ;********************************************************************************** 65 | ;shell flags 66 | 67 | int_state equ #8d72 ;apd_buf usage flag 68 | 69 | -------------------------------------------------------------------------------- /include/ti82parcus.inc: -------------------------------------------------------------------------------- 1 | ;********************************************************************************** 2 | ;include file for TI-82 Parcus/CrASH_19.006 3 | ;********************************************************************************** 4 | 5 | progstart equ #9104 ;all CrASH programs start here 6 | 7 | org progstart 8 | 9 | ;********************************************************************************** 10 | ;ports 11 | 12 | link equ #00 ;link port 13 | kbd equ #01 ;keyboard port 14 | rom equ #02 ;ROM page select port 15 | kon equ #03 ;ON key port 16 | lcd_crt equ #10 ;lcd control port 17 | lcd_data equ #11 ;ldc data port 18 | 19 | ;********************************************************************************** 20 | ;link port states 21 | 22 | lp_on equ #c3 ;link port off 23 | lp_off equ #c0 ;link port on 24 | lp_l equ #c1 ;link port left on 25 | lp_r equ #c2 ;link port right on 26 | lp_sw equ #03 ;toggle link port state 27 | lp_swl equ #01 ;toggle link port state left 28 | lp_swr equ #02 ;toggle link port state right 29 | lp_msk equ #c0c0 ;link port mask 30 | lp_smsk equ #c1c2 ;link port stereo mask 31 | 32 | ;********************************************************************************** 33 | ;saferam addresses 34 | 35 | graph_mem equ #88b8 ;768 bytes 36 | apd_buf equ #8228 ;768 bytes 37 | text_mem equ #808f ;128 bytes 38 | text_mem2 equ #8bdf ;128 bytes 39 | ops equ #8028 ;66 bytes 40 | 41 | mem_end equ #fcb3 ;user memory end (excl. safety margin) 42 | 43 | ;********************************************************************************** 44 | ;rom_call macro 45 | 46 | macro rom_call,addr 47 | call addr 48 | endm 49 | 50 | macro key_delay 51 | push hl 52 | pop hl 53 | endm 54 | 55 | ;********************************************************************************** 56 | ;rom calls 57 | 58 | clearlcd equ #39cd ;clear LCD, but not text or graphics memory 59 | cleartext_f equ #37A4 ;clear text_mem 60 | 61 | ;********************************************************************************** 62 | ;shell flags 63 | 64 | int_state equ #8d72 ;apd_buf usage flag 65 | 66 | -------------------------------------------------------------------------------- /include/ti83.inc: -------------------------------------------------------------------------------- 1 | ;********************************************************************************** 2 | ;include file for TI-83/Ion 1.6 3 | ;********************************************************************************** 4 | 5 | progstart equ #9327 ;all Ion programs start here 6 | 7 | org progstart 8 | xor a 9 | jr nc,begin 10 | ret 11 | 12 | ;********************************************************************************** 13 | ;ports 14 | 15 | link equ #00 ;link port 16 | kbd equ #01 ;keyboard port 17 | rom equ #02 ;ROM page select port 18 | kon equ #03 ;ON key port 19 | lcd_crt equ #10 ;lcd control port 20 | lcd_data equ #11 ;ldc data port 21 | 22 | ;********************************************************************************** 23 | ;link port states 24 | 25 | lp_on equ #d3 ;link port off 26 | lp_off equ #d0 ;link port on 27 | lp_l equ #d1 ;link port left on 28 | lp_r equ #d2 ;link port right on 29 | lp_sw equ #03 ;toggle link port state 30 | lp_swl equ #01 ;toggle link port state left 31 | lp_swr equ #02 ;toggle link port state right 32 | ;lp_msk equ #d3d3 ;link port mask 33 | lp_msk equ #d0d0 34 | lp_smsk equ #d1d2 ;link port stereo mask 35 | 36 | ;********************************************************************************** 37 | ;saferam addresses 38 | 39 | graph_mem equ #8E29 ;768 bytes 40 | apd_buf equ #8265 ;768 bytes 41 | text_mem equ #80C9 ;128 bytes 42 | text_mem2 equ #858F ;aka statram, 531 bytes 43 | ops equ #8039 ;66 bytes 44 | 45 | ;********************************************************************************** 46 | 47 | mem_end equ #f600 ;last byte of usr RAM 27463 vs 27118 (documented) 48 | 49 | ;********************************************************************************** 50 | ;rom_call macro 51 | 52 | macro rom_call,addr 53 | call addr 54 | endm 55 | 56 | macro key_delay 57 | nop 58 | nop 59 | endm 60 | 61 | ;********************************************************************************** 62 | ;rom calls 63 | 64 | clearlcd equ #4755 ;aka _clrlcdf 65 | 66 | ;********************************************************************************** 67 | ;shell flags 68 | 69 | ;int_state equ drumres ;apd_buf usage flag (disabled by pointing to 0 byte) 70 | -------------------------------------------------------------------------------- /include/ti8xp.inc: -------------------------------------------------------------------------------- 1 | ;********************************************************************************** 2 | ;include file for TI-83Plus/TI-84Plus/Ion-compatibles 3 | ;********************************************************************************** 4 | 5 | progstart equ #9d95 ;all 8x+ programs start here? 6 | ;progstart equ #9d93 ;all 8x+ programs start here? 7 | 8 | org progstart-2 9 | db #bb,#6d ;and are prefixed by a token 10 | xor a 11 | jr nc,begin 12 | ret 13 | 14 | ; jr begin 15 | ; dw 0 16 | ; db #07,#00 17 | ; ds 4 18 | 19 | 20 | ;********************************************************************************** 21 | ;ports 22 | 23 | link equ #00 ;link port 24 | kbd equ #01 ;keyboard port 25 | kon equ #04 ;ON key port??? 26 | rom equ #07 ;ROM page select port 27 | lcd_crt equ #10 ;lcd control port 28 | lcd_data equ #11 ;ldc data port 29 | 30 | ;********************************************************************************** 31 | ;link port states 32 | 33 | lp_on equ #03 ;link port off 34 | lp_off equ #00 ;link port on 35 | lp_l equ #01 ;link port left on 36 | lp_r equ #02 ;link port right on 37 | lp_sw equ #03 ;toggle link port state 38 | lp_swl equ #01 ;toggle link port state left 39 | lp_swr equ #02 ;toggle link port state right 40 | ;lp_msk equ #0303 ;link port mask 41 | lp_msk equ #0000 42 | lp_smsk equ #0102 ;link port stereo mask 43 | 44 | ;********************************************************************************** 45 | ;saferam addresses 46 | 47 | graph_mem equ #9340 ;aka plotscreen, 768 bytes 48 | apd_buf equ #9872 ;768 bytes 49 | text_mem equ #8508 ;128 bytes 50 | text_mem2 equ #8a3a ;aka statram, 531 bytes 51 | ops equ #8478 ;66 bytes 52 | 53 | ;********************************************************************************** 54 | 55 | ;ramend ;24079 (documented, ti83+) 56 | mem_end equ #f800 ;user memory end (excl. safety margin) In theory, up to ~FB00 would be possible 57 | 58 | ;********************************************************************************** 59 | ;rom_call macro 60 | 61 | macro rom_call,addr 62 | rst #28 63 | dw addr 64 | endm 65 | 66 | macro key_delay 67 | push hl 68 | pop hl 69 | endm 70 | 71 | ;********************************************************************************** 72 | ;rom calls 73 | 74 | clearlcd equ #4540 ;aka _clrlcdf 75 | 76 | ;********************************************************************************** 77 | 78 | -------------------------------------------------------------------------------- /include/ti8xs.inc: -------------------------------------------------------------------------------- 1 | ;********************************************************************************** 2 | ;include file for TI-83Plus/TI-84Plus/Ion-compatibles 3 | ;********************************************************************************** 4 | 5 | progstart equ #9d95 ;all 8x+ programs start here? 6 | ;progstart equ #9d93 ;all 8x+ programs start here? 7 | 8 | org progstart-2 9 | db #bb,#6d ;and are prefixed by a token 10 | xor a 11 | jr nc,begin 12 | ret 13 | 14 | ; jr begin 15 | ; dw 0 16 | ; db #07,#00 17 | ; ds 4 18 | 19 | 20 | ;********************************************************************************** 21 | ;ports 22 | 23 | link equ #00 ;link port 24 | kbd equ #01 ;keyboard port 25 | kon equ #04 ;ON key port??? 26 | rom equ #07 ;ROM page select port 27 | lcd_crt equ #10 ;lcd control port 28 | lcd_data equ #11 ;ldc data port 29 | 30 | ;********************************************************************************** 31 | ;link port states 32 | 33 | lp_on equ #03 ;link port off 34 | lp_off equ #00 ;link port on 35 | lp_l equ #01 ;link port left on 36 | lp_r equ #02 ;link port right on 37 | lp_sw equ #03 ;toggle link port state 38 | lp_swl equ #01 ;toggle link port state left 39 | lp_swr equ #02 ;toggle link port state right 40 | ;lp_msk equ #0303 ;link port mask 41 | lp_msk equ #0000 42 | lp_smsk equ #0102 ;link port stereo mask 43 | 44 | ;********************************************************************************** 45 | ;saferam addresses 46 | 47 | graph_mem equ #9340 ;aka plotscreen, 768 bytes 48 | apd_buf equ #9872 ;768 bytes 49 | text_mem equ #8508 ;128 bytes 50 | text_mem2 equ #8a3a ;aka statram, 531 bytes 51 | ops equ #8478 ;66 bytes 52 | 53 | ;********************************************************************************** 54 | 55 | ;ramend ;24079 (documented, ti83+) 56 | mem_end equ #f100 ;user memory end (excl. safety margin) In theory, up to ~FB00 would be possible 57 | 58 | ;********************************************************************************** 59 | ;rom_call macro 60 | 61 | macro rom_call,addr 62 | rst #28 63 | dw addr 64 | endm 65 | 66 | macro key_delay 67 | push hl 68 | pop hl 69 | endm 70 | 71 | ;********************************************************************************** 72 | ;rom calls 73 | 74 | clearlcd equ #4540 ;aka _clrlcdf 75 | 76 | ;********************************************************************************** 77 | 78 | -------------------------------------------------------------------------------- /init.asm: -------------------------------------------------------------------------------- 1 | ;************************************************************************************ 2 | ;the startup code 3 | ;************************************************************************************ 4 | 5 | IF MODEL = TI82 || MODEL = TI8P 6 | checkAPD_FREE ;check if APD_BUF is in use 7 | ld a,(int_state) 8 | or a 9 | ret nz ;exit if it is. ->TODO: add error msg 10 | ENDIF 11 | 12 | IF MODEL != TI83 13 | rom_call(clearlcd) 14 | ENDIF 15 | di 16 | 17 | push iy 18 | push ix 19 | 20 | ld (exitSP),sp ;preserve stack 21 | 22 | ;IF MODEL != TI8X ;setting ROM to a different page crashes TI83 23 | IF MODEL = TI82 || MODEL = TI8P 24 | ld a,%10001001 ;set ROM page 1 25 | out (rom),a 26 | ENDIF 27 | 28 | IF MODEL = TI8X || MODEL = TI8XS 29 | in a,(2) ;detect hardware 30 | ld b,a 31 | and #80 ;if bit 7 is set, we have TI83+ BASIC 32 | jr z,reinit0 33 | 34 | xor a 35 | out (#20),a ;set 6 MHz mode 36 | out (8),a ;disable link assist 37 | 38 | in a,(21h) 39 | and 3 40 | jr z,usbdeact ;TI84+ SE 41 | bit 5,b 42 | jr z,reinit0 ;TI83+ SE 43 | 44 | usbdeact ;TI84+/SE detected, deactivating USB to save power 45 | xor a 46 | out (#57),a 47 | out (#5b),a 48 | out (#4c),a 49 | ld a,2 50 | out (#54),a 51 | ENDIF 52 | 53 | reinit0 54 | ld a,#16 55 | ex af,af' 56 | reinit 57 | ld hl,apd_buf ;clear APD_BUF 58 | ld de,apd_buf+1 59 | ld bc,767 60 | xor a 61 | ld (hl),a 62 | ldir 63 | 64 | ex af,af' 65 | ld (StateSelect),a 66 | 67 | ;************************************************************************************ 68 | ; genDrum ;generate kick drum sample in text_mem 69 | ; ld d,1 ;1 70 | ; ld a,#80 ;2 71 | ; ld hl,text_mem ;3 72 | ; _xlp 73 | ; ld b,d ;1 74 | ; _lp 75 | ; ld (hl),a ;1 76 | ; inc hl ;1 77 | ; djnz _lp ;2 78 | ; 79 | ; inc d ;1 80 | ; sub #11 ;2 81 | ; 82 | ; jr nc,_xlp ;2 83 | ; 84 | ; add a,#11 ;2 85 | ; srl a ;2 86 | ; 87 | ; jr nz,_xlp ;2 88 | ; 89 | ; _exit 90 | ; ld (hl),a ;1 91 | ; ;23b 92 | 93 | generatePtnTabs ;generate pattern table and fx pattern table 94 | 95 | ld (_restSP),sp ;save stack pointer 96 | ld sp,256*((HIGH(ptntab))+1) 97 | 98 | ld de,#10 99 | ld hl,ptn00+(#7f*#10) ;HL = address of pnt #7f 100 | ld b,#80 101 | 102 | _lp 103 | push hl ;push ptn address 104 | sbc hl,de ;sub #10 105 | djnz _lp ;rinse and repeat 106 | 107 | ld sp,fxptntab+128 108 | sla e ;DE = #20 109 | ld hl,fxptn00+(#3f*#20) 110 | ld b,#40 111 | 112 | _lp2 113 | push hl 114 | sbc hl,de 115 | djnz _lp2 116 | 117 | _restSP equ $+1 118 | ld sp,0 ;restore stack pointer 119 | 120 | ;************************************************************************************ 121 | generateCounterLUT ;generate note counter value table 122 | 123 | ld hl,baseCounterLUT ;copy BaseCounterLUT to APD_BUF at [oct. 6] 124 | ld de,NoteTab+(1+12*6)*2 ;table will be created on 3rd page of APD_BUF. Each note counter is a word. 125 | ;length of LUT = silence (2 bytes) and then 7 octaves (168 bytes) 126 | ld bc,2*12 127 | ldir ;execute copy 128 | 129 | ld hl,NoteTab+(1+12*6)*2-1 ;start reverse calculation of lower octaves at [oct. 6]-1, de already points to last byte of LUT 130 | ld b,12*6 ;calculating 6 octaves of notes 131 | 132 | _lp 133 | dec e ;decrement source pointer (it's initially 1 too high from previous ldir) 134 | xor a ;clear carry 135 | ld a,(de) ;load hi byte 136 | rra ;divide by 2 137 | ld (hl),a ;store 138 | dec e ;decrement pointers 139 | dec l 140 | ld a,(de) ;load lo byte 141 | rra ;divide by 2 and rotate in carry from hi byte 142 | ld (hl),a ;store 143 | dec l ;decrement target pointer 144 | djnz _lp ;rinse and repeat 145 | 146 | ;************************************************************************************ 147 | generateCsrLUT ;generate cursor position table 148 | ;LUT format: byte 1 = Horiz. + set bit 7 for #f0 cursor; byte 2 = vert. 149 | ld c,10 ;10 rows 150 | ld a,#87 ;first row vertical offset = #87 151 | ld hl,CsrTab+1 ;start at 2nd page of graph_mem + 1 152 | 153 | _lpo ;generate vertical positions 154 | ld b,8 ;4*2 bytes per row 155 | _lpi 156 | ld (hl),a 157 | inc l 158 | inc l 159 | djnz _lpi 160 | add a,6 161 | dec c 162 | jr nz,_lpo 163 | 164 | ld b,10 165 | ld l,0 ;reset LUT pointer 166 | 167 | _lp2 168 | ld a,#21 169 | ld (hl),a ;21 170 | inc l 171 | inc l 172 | add a,#81 ;inc a \ add a,#80 173 | ld (hl),a ;22+80 174 | inc l 175 | inc l 176 | inc a 177 | ld (hl),a ;23+80 178 | inc l 179 | inc l 180 | sub #80 ;A-80 181 | ld (hl),a ;23 182 | inc l 183 | inc l 184 | inc a 185 | ld (hl),a ;24 186 | inc l 187 | inc l 188 | add a,#81 189 | ld (hl),a ;25+80 190 | inc l 191 | inc l 192 | inc a 193 | ld (hl),a ;26+80 194 | inc l 195 | inc l 196 | sub #80 197 | ld (hl),a ;26 198 | inc l 199 | inc l 200 | djnz _lp2 201 | 202 | _generatePtnCsr ;generating pattern screen cursor positions at offset #50*2 203 | ld d,#21 204 | call fillTable 205 | ld d,#22+#80 206 | call fillTable 207 | ld d,#25 208 | call fillTable 209 | ld d,#26+#80 210 | call fillTable 211 | 212 | _generateFxCsr ;generate fx screen cursor positions at text_mem 213 | ld hl,CsrTab2 214 | ld d,#21+#80 215 | call fillTable 216 | ld d,#21 217 | call fillTable 218 | ld d,#22+#80 219 | call fillTable 220 | ld d,#22 221 | call fillTable 222 | ld d,#25+#80 223 | call fillTable 224 | ld d,#25 225 | call fillTable 226 | ld d,#26+#80 227 | call fillTable 228 | ld d,#26 ;THIS CAUSES THE "LOW CONTRAST BUG" 229 | call fillTable ;8 bytes is ok, 10 is too much - because it starts to write at #8000, d'uh 230 | 231 | jr unpackFont 232 | 233 | fillTable ;fill a chunk of the cursor position LUTs 234 | ld b,8 235 | ld a,#93 236 | _lp 237 | ld (hl),d 238 | inc l 239 | ld (hl),a 240 | inc l 241 | add a,6 242 | djnz _lp 243 | ret 244 | 245 | ;************************************************************************************ 246 | unpackFont ;unpack the font 247 | ld hl,font 248 | ld de,FontLUT ;unpacked font will be created in APD_BUF (TI82 at #8300) 249 | push de ;preserve pointer to unpacked font 250 | 251 | ld b,cmprFontSize ;unpacking all the font bytes 252 | or a ;clear carry 253 | 254 | unpackFontLP 255 | ld a,(hl) ;load compressed char byte 256 | and %11110000 257 | ld (de),a ;save unpacked byte 258 | inc de ;increment pointer to unpacked font 259 | ld a,(hl) ;load compressed char byte again 260 | add a,a ;shift left 4 bits 261 | add a,a 262 | add a,a 263 | add a,a 264 | ld (de),a 265 | inc de 266 | inc hl 267 | djnz unpackFontLP 268 | 269 | dec de ;when uneven amount of chars, last unpacked byte is irrelevant and can be overwritten. TODO: Use IF/ENDIF 270 | pop hl ;retrieve pointer to unpacked font 271 | 272 | ;create right-shifted chars from unpacked font 273 | 274 | ld b,charNumShifted*5 ;amount of chars to shift, use only the necessary ones 275 | or a ;clear carry 276 | 277 | shiftFontLP 278 | ld a,(hl) ;load unshifted pixel row 279 | rra ;shift right 4 pixels 280 | rra 281 | rra 282 | rra 283 | ld (de),a ;save unpacked byte 284 | inc de 285 | inc hl 286 | djnz shiftFontLP 287 | 288 | 289 | initSCR ;draw the basic screen layout 290 | ld a,#f2 ;modify setXY code to use longer wait lp 291 | ld (setXYmod),a 292 | 293 | setXYat #20, #80 ;select column 0, row 0 294 | 295 | ld a,7 ;cursor direction right 296 | out (lcd_crt),a 297 | call lcdWait3 298 | 299 | ld b,#c ;12*8=96 pixel 300 | ld a,#ff ;data to write 301 | 302 | call drawLoop ;draw a line on top of the screen 303 | 304 | setXYat #29, #81 305 | 306 | ld a,5 ;cursor direction down 307 | out (lcd_crt),a 308 | call lcdWait3 309 | 310 | ld b,a ;ld b,5 311 | ld c,a ;preserve 5 in c because we'll need that constant a few more times 312 | ld a,#ff 313 | call drawLoop ;draw black block next to the logo 314 | 315 | setXYat #28, #81 316 | 317 | ld b,c ;ld b,5 318 | ld a,%00101111 319 | 320 | _drawlp ;draw fancy block left of the black block 321 | out (lcd_data),a 322 | call lcdWait3 323 | sra a 324 | djnz _drawlp 325 | 326 | setXYat #2a, #81 ;draw HT2 logo in the top right corner 327 | 328 | ld hl,htlogo 329 | ld b,c ;ld b,5 330 | call drawlp2 331 | 332 | setXYat #2b, #81 333 | 334 | ld b,c ;ld b,5 335 | call drawlp2 336 | 337 | ld a,#f4 ;modify setXY code to use shorter wait lp 338 | ld (setXYmod),a 339 | 340 | 341 | printVarNames ;create global var names on the right side 342 | 343 | setXYat #2a, #ac ;reset RowPlay indicator 344 | call clearPrintBuf ;clear print buffer 345 | call printBuf 346 | 347 | ld a,(StateSelect) 348 | call printSaveSlotIndicator 349 | 350 | call printPlayModeIndicator ;print STOP char 351 | 352 | ld hl,varmsgs ;load chars 353 | ld b,4 ;4 messages to print 354 | 355 | _rdlp 356 | ld d,(hl) 357 | inc hl 358 | ld e,(hl) 359 | push hl 360 | push bc 361 | 362 | call printDE ;print the chars held in DE 363 | 364 | pop bc 365 | pop hl 366 | inc hl 367 | djnz _rdlp 368 | 369 | ld a,CHAR_D ;print a "D" (as in usr Drum) 370 | call printCharL 371 | 372 | ld a,1 373 | ld (AutoInc),a 374 | 375 | printTwoChars CHAR_A, CHAR_0 ;print AutoInc indicator 376 | 377 | p123D 378 | ld a,#9f ;reset mute states 379 | ld (mute1),a 380 | ld (mute2),a 381 | ld (mute3),a 382 | ld a,#d2 383 | ld (muteD),a 384 | 385 | call printMute12 ;print channel active/mute info (123D) 386 | call printMute3D 387 | 388 | 389 | ;end of screen initialization 390 | ;************************************************************************************ 391 | 392 | printVars ;print global var names 393 | 394 | ld a,(looprow) ;temporary set loop point 395 | call printCharsNoFF ;print them 396 | 397 | ld a,(speed) ;load global speed 398 | call printCharsNoFF ;print 399 | 400 | ld a,(CPS) 401 | call printCharsNoFF ;print 402 | 403 | ld a,(CPE) 404 | call printCharsNoFF ;print 405 | 406 | ld a,(usrDrum) ;print lo byte of usr drum pointer 407 | call printChars 408 | 409 | setXYat #2a, #a6 410 | 411 | ld a,(usrDrum+1) ;print hi byte of usr drum pointer 412 | call printChars 413 | 414 | ; checkSavestate 415 | ; ld a,(version) 416 | ; or a 417 | ; jr z,ldok 418 | ; ld a,#6 419 | ; call errorHand 420 | ldok 421 | 422 | 423 | call printSeqScr ;print the main (sequence) screen 424 | 425 | call initSeqCsr ;init cursor 426 | 427 | -------------------------------------------------------------------------------- /keyhand.asm: -------------------------------------------------------------------------------- 1 | ;************************************************************************************ 2 | ;the key handler 3 | ;************************************************************************************ 4 | 5 | waitForKeyRelease ;wait for key release function. 6 | 7 | _rdkeys 8 | in a,(kbd) 9 | cpl ;4 ;would be nice to skip these two lines 10 | or a ;4 ;but somehow that doesn't work 11 | jr nz,_rdkeys 12 | 13 | _wait 14 | ld b,a 15 | 16 | ld a,(LastKey) ;reset ALPHA mode if last key pressed was not ALPHA 17 | or a 18 | jr nz,_resetLK 19 | 20 | xor a 21 | ld (AlphaFlag),a 22 | 23 | setXYat #28, #88 24 | call clearPrintBuf ;clear print buffer 25 | call printBuf ;remove Alpha mode marker from screen 26 | ;ld b,0 ;unnecessary, printBuf returns with b=0 anyway 27 | jr _waitlp 28 | 29 | _resetLK 30 | xor a ;clear LastKey flag 31 | ld (LastKey),a 32 | 33 | _waitlp ;waiting for keypad bounce 34 | ex (sp),hl 35 | ex (sp),hl 36 | ld a,(hl) 37 | ;IF MODEL = TI83 || MODEL = TI8X || MODEL = TI8XS 38 | IF MODEL != TI82 39 | ld a,(hl) 40 | ENDIF 41 | djnz _waitlp 42 | 43 | ret ;5 44 | 45 | ;******************************************************************************* 46 | inputSlotNr 47 | ld a,KBD_GROUP_ZERO 48 | out (kbd),a 49 | key_delay 50 | in a,(kbd) 51 | rra 52 | jr nc,ik0 53 | rra 54 | jr nc,ik1 55 | rra 56 | jr nc,ik4 57 | rra 58 | jr nc,ik7 59 | 60 | ld a,KBD_GROUP_DOT 61 | out (kbd),a 62 | key_delay 63 | in a,(kbd) 64 | rra 65 | rra 66 | jr nc,ik2 67 | rra 68 | jr nc,ik5 69 | 70 | ld a,KBD_GROUP_MINUS ;group (-)/3/6/9/)/G/VARS 71 | out (kbd),a 72 | key_delay 73 | in a,(kbd) 74 | rra 75 | rra 76 | jr nc,ik3 77 | rra 78 | jr nc,ik6 79 | jr inputSlotNr 80 | 81 | ik0 82 | ld b,0 83 | jr kSlotSelect 84 | ik1 85 | ld b,1 86 | jr kSlotSelect 87 | ik2 88 | ld b,2 89 | jr kSlotSelect 90 | ik3 91 | ld b,3 92 | jr kSlotSelect 93 | ik4 94 | ld b,4 95 | jr kSlotSelect 96 | ik5 97 | ld b,5 98 | jr kSlotSelect 99 | ik6 100 | ld b,6 101 | jr kSlotSelect 102 | ik7 103 | ld b,7 104 | 105 | 106 | kSlotSelect ;print state selection, and update it 107 | setXYat #2b, #b2 108 | 109 | ld a,b 110 | 111 | ld (StateSelect),a ;store selected state 112 | 113 | jr reprint 114 | ;call printCharL ;reprint current 115 | 116 | ;xor a 117 | ;ld (InputType),a ;reset input type 118 | 119 | ;call printCsr ;print cursor 120 | 121 | ;jp waitForKeyRelease 122 | 123 | ;************** 124 | 125 | inputSingle ;aka set current octave 126 | 127 | setXYat #23, #88 128 | 129 | ld a,b 130 | cp 7 ;check if input digit is in range 0..6 131 | ret nc ;ignore keypress if it isn't 132 | 133 | ld (COct),a ;store new current oct 134 | 135 | reprint 136 | call printCharL ;reprint current oct 137 | 138 | xor a 139 | ld (InputType),a ;reset input type 140 | 141 | jp kdirskip2 ;print cursor & wait for key release 142 | 143 | inputDouble ;input a double digit hex value 144 | ;IN: set iPrintPos and iUpdatePos 145 | push af 146 | 147 | iPrintPos equ $+1 148 | ld de,0 149 | call setXY 150 | 151 | iUpdatePos equ $+1 152 | ld hl,0 153 | 154 | pop af 155 | rra 156 | jr c,inputDoubleLow ;if input val=6, we're inputting the low nibble 157 | 158 | ld a,6 ;the next hex input should be a low nibble 159 | ld (InputType),a 160 | 161 | ld a,b ;load input digit 162 | push af 163 | 164 | add a,a 165 | add a,a 166 | add a,a 167 | add a,a 168 | 169 | ld (hl),a 170 | 171 | pop af 172 | call printCharL ;print it as upper nibble 173 | 174 | iDUpdate 175 | jp waitForKeyRelease 176 | ;ret 177 | 178 | inputDoubleLow 179 | xor a ;reset input type 180 | ld (InputType),a 181 | 182 | ld a,b 183 | or (hl) 184 | ld (hl),a 185 | 186 | call printCharsNoFF 187 | 188 | ld a,(CScrType) ;check what type of cursor to print 189 | cp 2 190 | jr nz,_normal 191 | call printCsr2 192 | jr wordSwitch-1 193 | _normal 194 | call printCsr 195 | 196 | wordSwitch equ $+1 197 | ld a,0 198 | or a 199 | jr z,iDUpdate 200 | 201 | xor a 202 | ld (wordSwitch),a 203 | 204 | call waitForKeyRelease 205 | ld hl,usrDrum 206 | setXYat #2b, #a6 207 | jp kSetBFull 208 | 209 | 210 | inputWord 211 | ex af,af' 212 | ld a,1 213 | ld (wordSwitch),a 214 | ex af,af' 215 | jr inputDouble 216 | 217 | 218 | kHexInp ;handle hex digit input 219 | 220 | ld b,a ;preserve the input value 221 | 222 | or a ;clear carry 223 | ld a,(InputType) ;determine input type 224 | rra 225 | jp c,inputSingle 226 | rra 227 | jp c,inputDouble 228 | rra 229 | jp c,inputWord 230 | 231 | ld a,(CScrType) ;check screen type 232 | or a 233 | jp nz,kHexNoSeq 234 | 235 | call getSeqOffset ;now seq. pointer in HL, current ptn# in (CPtn) 236 | 237 | ld a,(AlphaFlag) ;check for Alpha mode 238 | or a 239 | jr z,_noalpha 240 | ld a,b ;check if input char was 0 241 | or a 242 | jr nz,_noalpha ;if both Alpha mode and 0, delete pattern # at cursor 243 | 244 | ld a,#ff 245 | ld (hl),a 246 | 247 | jp pagescroll+3 248 | ;ld a,(CsrPos) 249 | ;ld (OldCsrPos),a 250 | ;call printSeqScr0 251 | ;call printCsr 252 | ;jp waitForKeyRelease 253 | 254 | _noalpha 255 | ld a,(CsrPos) ;check whether we need to shift the digit to upper nibble 256 | rra 257 | ld a,b ;retrieve input value 258 | jr c,_noShift 259 | add a,a ;shift left 4 bits 260 | add a,a 261 | add a,a 262 | add a,a 263 | ld b,a 264 | ld a,(CPtn) ;load current ptn value 265 | and %00001111 ;delete upper nibble 266 | jr _byteUpdate 267 | 268 | _noShift 269 | ld a,(CPtn) ;load current ptn value 270 | and %11110000 ;delete lower nibble 271 | 272 | _byteUpdate 273 | or b ;combine with input value 274 | ld e,a ;preserve in E 275 | 276 | ld d,#7f ;make sure ptn# does not exceed #7f 277 | ld a,(CsrPos) ;check column type 278 | and 7 ;mask out bits that are irrelevant to horizontal pos 279 | cp 6 280 | jr c,_skip ;if column > 5 281 | ld d,#3f ;we're setting fx ptn# - make sure it doesn't exceed #3f 282 | _skip 283 | ld a,e 284 | and d 285 | ld (hl),a ;and store it at song pointer 286 | ld (CPtn),a 287 | 288 | call setPrintPos 289 | call updateSeqScr 290 | 291 | ld a,(AutoInc) ;check AutoInc mode 292 | or a 293 | 294 | ;jp z,kright 295 | jp z,kRnoalpha ;if AutoInc mode is on, update cursor as if RIGHT key had been pressed 296 | ;jp printCsr ;else, simply reprint the cursor at the current position 297 | jp kdirskip2 298 | 299 | 300 | updateSeqScr ;update an entry on the sequence screen 301 | ld a,(CsrPos) ;load cursor pos 302 | and 3 ;check what type of column is being printed 303 | cp 0 ;and select the print function accordingly 304 | jr z,uRight 305 | cp 1 306 | jr z,uLeft 307 | 308 | uBoth 309 | ld a,(CPtn) 310 | jp printChars 311 | ;ret 312 | 313 | uRight 314 | ld a,(CPtn) 315 | push de 316 | call printCharR 317 | pop de 318 | inc d 319 | call setXY 320 | ld a,(CPtn) 321 | jp printCharL 322 | ;ret 323 | 324 | uLeft 325 | ld a,(CPtn) 326 | push de 327 | call printCharL 328 | pop de 329 | dec d 330 | call setXY 331 | ld a,(CPtn) 332 | jp printCharR 333 | ;ret 334 | 335 | ;************************************************************************************ 336 | kHexNoSeq ;handling input on ptn screen 337 | ;IN: B=hex digit 338 | dec a ;check if we're on an fx ptn screen 339 | jp nz,kHexFX 340 | 341 | kHexPtn 342 | call findCurrPtn ;get ptn pointer into DE 343 | ld h,0 344 | ld a,(CsrPos) ;get cursor position 345 | ld c,a ;preserve it in C 346 | cpl ;convert it to ptn data offset 347 | and #10 348 | rrca 349 | ld l,a 350 | ld a,c 351 | and #7 352 | add a,l 353 | ld l,a 354 | 355 | add hl,de ;position to edit now referenced by HL 356 | push hl ;a08a 357 | 358 | ld a,c ;retrieve cursor position and determine if input is a note name or an octave 359 | and 8 360 | ld a,b ;retrieve input digit 361 | jr nz,inputOct 362 | 363 | inputNote 364 | or a 365 | jr z,_exitlp 366 | 367 | cp #a ;check if input digit is A..G... handle G seperatly? 368 | jp c,ignoreKeypress ;ignore keypress if it isn't 369 | 370 | ld c,a ;preserve input digit in C 371 | 372 | ld hl,notevals ;load note val conversion LUT pointer 373 | add a,l ;add offset 374 | ld l,a 375 | 376 | ld a,(COct) ;fetch current octave 377 | ld b,a 378 | inc b 379 | 380 | ld a,(AlphaFlag) ;check if ALPHA mode is active 381 | or a 382 | jr z,_skip ;if it is 383 | 384 | ld a,#b ;check if input note was a B 385 | sub c 386 | jr z,_skip ;skip raising halftone if it was 387 | 388 | ld a,1 ;add a half-tone (TODO: check if it's a valid halftone - or ignore and always go a halftone higher, also fine) 389 | _skip 390 | add a,(hl) ;get base note val 391 | ld c,a ;preserve it in C 392 | _lp 393 | dec b 394 | jp z,_exitlp 395 | add a,12 396 | jr _lp 397 | 398 | _exitlp ;note val now in A 399 | pop hl 400 | ld (hl),a ;update note byte 401 | or a 402 | jr z,reprintDash 403 | 404 | _reprint 405 | call setPrintPos 406 | 407 | push de 408 | 409 | ld a,c ;restore base note val 410 | dec a ;note names are offset by 1, correct it 411 | ld hl,notenames ;point to note name LUT 412 | add a,a ;A=A*2 413 | ld e,a 414 | ld d,0 415 | add hl,de ;add offset to LUT pointer 416 | 417 | ld d,(hl) ;get string into DE 418 | inc hl 419 | ld e,(hl) 420 | 421 | call printDE 422 | pop de ;retrieve print pos 423 | inc d ;inc horiz. pos by 1 424 | call setXY 425 | 426 | ld a,(COct) ;print current octave 427 | call printCharL 428 | 429 | ld a,(RowPlay) 430 | or a 431 | call nz,rowPlay 432 | 433 | skipRP 434 | ld a,(AutoInc) ;move cursor down if AutoInc is enabled 435 | or a 436 | jp z,kpdown 437 | jp kdirskip2 ;else return normally 438 | 439 | 440 | reprintDash ;print dashes if new note byte = 0 441 | call setPrintPos 442 | push de 443 | 444 | printTwoChars CHAR_DASH, CHAR_DASH 445 | 446 | pop de 447 | inc d 448 | call setXY 449 | 450 | call clearPrintBuf 451 | ld a,CHAR_DASH 452 | call printCharLNC 453 | 454 | jr skipRP 455 | 456 | 457 | inputOct 458 | pop hl 459 | cp 7 ;check if input digit is 0..6 460 | jp nc,ignoreKeypress+1 ;ignore keypress if it isn't 461 | push bc 462 | 463 | ld a,(hl) ;load current note val 464 | or a ;if no note is set 465 | jp z,ignoreKeypress ;ignore keypress 466 | 467 | call divNoteVal ;returns current octave in B, base note val in C 468 | 469 | ld a,c 470 | pop bc 471 | ld c,b ;preserve input digit (new octave) in C 472 | inc b 473 | 474 | _lp 475 | dec b 476 | jr z,_skip 477 | add a,12 ;for each octave >0, add 12 to base note val 478 | jr _lp 479 | _skip 480 | inc a ;note vals are offset by 1 481 | ld (hl),a ;store new load value 482 | 483 | call setPrintPos 484 | 485 | ld a,c ;retrieve input digit (new oct) 486 | 487 | call printCharL ;print it 488 | jr skipRP ;and update cursor 489 | 490 | 491 | ;************************************************************************************ 492 | kHexFX ;handle hex input on fx ptn scr 493 | ;IN: B=hex digit 494 | 495 | ld a,(CPtn) ;locate current fx ptn in mem 496 | ld hl,fxptntab 497 | call findCurrFxPtn ;ptn pointer now in DE 498 | 499 | ld hl,0 500 | ld a,(CsrPos) ;read cursor position 501 | ld c,a ;backup in C 502 | bit 4,a ;convert cursor position into ptn data offset 503 | jr z,_skip3 504 | inc l 505 | _skip3 506 | and #20 507 | rrca 508 | add a,l 509 | ld l,a 510 | ld a,c 511 | and #7 512 | rlca 513 | add a,l 514 | ld l,a 515 | 516 | add hl,de ;byte to edit now referenced by HL 517 | 518 | ld a,c ;restore csrpos 519 | and %00001000 ;determine whether input is hi or low nibble 520 | ld a,b ;restore input val 521 | jr nz,_skip ;if Z then it's a hi nibble 522 | add a,a ;shift input value left 4 bits 523 | add a,a 524 | add a,a 525 | add a,a 526 | ld b,a 527 | ld a,(hl) 528 | and %00001111 ;clear upper nibble 529 | jr _set 530 | _skip 531 | ld a,(hl) 532 | and %11110000 ;clear lower nibble 533 | _set 534 | or b ;combine low and hi nibble 535 | ld (hl),a 536 | 537 | ld c,a 538 | ld hl,CsrTab2 539 | call setPrintPosFx 540 | ld a,c 541 | 542 | call printCharsNoFF 543 | 544 | ld a,(AutoInc) 545 | or a 546 | jp z,kfdown 547 | 548 | call printCsr2 549 | jp waitForKeyRelease 550 | 551 | ignoreKeypress 552 | pop hl ;clear stack 553 | ;ret ;and back to where we came from 554 | jp waitForKeyRelease 555 | 556 | ;************************************************************************************ 557 | setPrintPos ;set print position based on current cursor pos 558 | ;IN: nothing | OUT: print pos set and in DE; HL, A destroyed 559 | ld hl,CsrTab 560 | setPrintPosFx ;entry point for FX patterns, HL must be set to CsrTab2 561 | ld a,(CsrPos) 562 | add a,a 563 | add a,l 564 | ld l,a 565 | ld a,(hl) 566 | and %01111111 ;mask out bit 7 since cursor type is irrelevant at this point 567 | ld d,a 568 | inc l 569 | ld a,(hl) 570 | sub 5 ;actual horiz. pos = CsrPos - 5 571 | ld e,a 572 | jp setXY ;using the ret from setXY 573 | 574 | ;************************************************************************************ 575 | kfdown 576 | call delCsr2 ;delete cursor 577 | ld a,(CsrPos) 578 | inc a ;jump to next row 579 | ld d,a 580 | and %00000111 581 | or a 582 | ld a,d 583 | jr nz,kdirskipF ;if bottom row reached 584 | add a,#18 ;jump to top of same column, 2nd half 585 | cp #40 586 | jr c,kdirskipF ;if bottom row on 2nd half reached 587 | sub #40 ;jump to top of same colum, 1st half 588 | 589 | kdirskipF 590 | ld (CsrPos),a 591 | call printCsr2 592 | jp waitForKeyRelease 593 | ;ret 594 | 595 | kfleft 596 | ld a,(AlphaFlag) ;check Alpha mode 597 | or a 598 | jr z,_noalpha 599 | ;if Alpha is on, cycle through patterns 600 | setXYat #23, #82 ;TODO: optimize | set printing pos 601 | 602 | ld a,(CPtn) ;increment "current pattern" value 603 | dec a 604 | and #3f ;make sure we don't go above #7f 605 | ld (CPtn),a 606 | 607 | jp printFxScrNoInit ;and print the new pattern 608 | 609 | _noalpha 610 | call delCsr2 ;delete cursor 611 | ld a,(CsrPos) 612 | sub 8 ;jump to previous column 613 | jr nc,kdirskipF ;if already in the 1st column 614 | add a,#40 ;wrap to last column 615 | jr kdirskipF 616 | 617 | kfright 618 | ld a,(AlphaFlag) ;check Alpha mode 619 | or a 620 | jr z,_noalpha 621 | ;if Alpha is on, cycle through patterns 622 | setXYat #23, #82 ;TODO: optimize | set printing pos 623 | 624 | ld a,(CPtn) ;increment "current pattern" value 625 | inc a 626 | and #3f ;make sure we don't go above #7f 627 | ld (CPtn),a 628 | 629 | jp printFxScrNoInit ;and print the new pattern 630 | 631 | _noalpha 632 | call delCsr2 ;delete cursor 633 | ld a,(CsrPos) 634 | add a,8 ;jump to next column 635 | cp #40 636 | jr c,kdirskipF ;if already in the last column 637 | sub #40 ;wrap to first column 638 | jr kdirskipF 639 | 640 | kfup 641 | call delCsr2 642 | ld a,(CsrPos) 643 | dec a 644 | ld d,a 645 | and %00000111 646 | cp #7 647 | ld a,d 648 | jr nz,kdirskipF 649 | sub #18 ;#ff-#18 doesn't set carry, 650 | or a ;so we need to check if result was negative 651 | jp p,kdirskipF ;like that 652 | add a,#40 653 | jr kdirskipF 654 | 655 | 656 | kpdown 657 | call delCsr ;delete cursor 658 | ld a,(CsrPos) 659 | inc a ;jump to next row 660 | ld d,a 661 | and %00000111 662 | or a ;TODO: redundant? 663 | ld a,d 664 | jp nz,kdirskip ;if bottom row reached 665 | add a,#8 ;jump to top of same column, 2nd half 666 | cp #70 667 | jp c,kdirskip ;if bottom row on 2nd half reached 668 | sub #20 ;jump to top of same colum, 1st half 669 | jp kdirskip 670 | 671 | kpleft 672 | ld a,(AlphaFlag) ;check Alpha mode 673 | or a 674 | jr z,_noalpha 675 | ;if Alpha is on, cycle through patterns 676 | setXYat #23, #82 ;TODO: optimize | set printing pos 677 | 678 | ld a,(CPtn) ;increment "current pattern" value 679 | dec a 680 | and #7f ;make sure we don't go above #7f 681 | ld (CPtn),a 682 | 683 | jp printPtnScrNoInit ;and print the new pattern 684 | 685 | _noalpha 686 | call delCsr 687 | ld a,(CsrPos) 688 | sub 8 689 | cp #50 690 | jp nc,kdirskip 691 | add a,#20 692 | jp kdirskip 693 | 694 | kpright 695 | ld a,(AlphaFlag) ;check Alpha mode 696 | or a 697 | jr z,_noalpha 698 | ;if Alpha is on, cycle through patterns 699 | setXYat #23, #82 ;TODO: optimize | set printing pos 700 | 701 | ld a,(CPtn) ;increment "current pattern" value 702 | inc a 703 | and #7f ;make sure we don't go above #7f 704 | ld (CPtn),a 705 | 706 | jp printPtnScrNoInit ;and print the new pattern 707 | 708 | _noalpha ;do normal cursor movement 709 | call delCsr 710 | ld a,(CsrPos) 711 | add a,8 712 | cp #70 713 | jp c,kdirskip 714 | sub #20 715 | jp kdirskip 716 | 717 | kpup 718 | call delCsr 719 | ld a,(CsrPos) 720 | dec a 721 | ld d,a 722 | and %00000111 723 | cp #7 724 | ld a,d 725 | jp nz,kdirskip 726 | sub #8 727 | cp #50 728 | jp nc,kdirskip 729 | add a,#20 730 | jp kdirskip 731 | 732 | kup 733 | ld a,(CsrPos) 734 | ld (OldCsrPos),a 735 | ld a,(AlphaFlag) 736 | or a 737 | jr z,kuskip 738 | xor a 739 | ld (FirstLineMS),a 740 | call printSeqScr 741 | jp kdirskip2 742 | 743 | kuskip 744 | call delCsr ;delete cursor 745 | ld a,(CsrPos) 746 | sub 8 ;subtract 8 from cursor pos 747 | jp nc,kdirskip ;and that's it, unless cursor is about to go off-screen 748 | 749 | ld a,(FirstLineMS) ;in that case, check what's the first line of sequence data on screen 750 | or a 751 | jp z,kdirskip2 ;if it's 0, don't change anything and that's it 752 | 753 | dec a ;else, decrement FirstLine 754 | ;ld (FirstLineMS),a ;and store it 755 | ;call printSeqScr0 ;reprint sequence screen (without setting screen type / kdir jump table offset) 756 | ;jp kdirskip2 757 | jr seqScrReprint 758 | 759 | kright 760 | ld a,(AlphaFlag) ;check for Alpha mode 761 | or a 762 | jr z,kRnoalpha 763 | ld a,(FirstLineMS) ;if Alpha mode is set, scroll 1 page (10 lines) 764 | add a,#a ;add 10 to FirstLine 765 | pagescroll0 766 | cp #f7 767 | jr c,pagescroll ;if result is >#f6 768 | ld a,#f6 ;set FirstLine to #f6 769 | pagescroll 770 | ld (FirstLineMS),a 771 | reprintX 772 | ld a,(CsrPos) 773 | ld (OldCsrPos),a 774 | reprintY 775 | call printSeqScr0 776 | call printCsr 777 | jp waitForKeyRelease 778 | 779 | kRnoalpha 780 | call delCsr 781 | ld a,(CsrPos) 782 | inc a 783 | cp #50 ;check if cursor pos limit reached 784 | jr nz,kdirskip 785 | ;xor a 786 | ld a,#48 ;if yes, move cursor to beginning of the same row 787 | ld (OldCsrPos),a 788 | jr kdskip+3 ;and scroll screen 789 | 790 | kdown 791 | ld a,(CsrPos) 792 | ld (OldCsrPos),a 793 | ld a,(AlphaFlag) 794 | or a 795 | jr z,kdskip 796 | 797 | ld a,#f6 798 | ld (FirstLineMS),a 799 | call printSeqScr 800 | jr kdirskip2 801 | 802 | kdskip 803 | call delCsr 804 | ld a,(CsrPos) 805 | add a,8 806 | cp #50 807 | jr c,kdirskip 808 | 809 | ld a,(FirstLineMS) ;need to implement scroll/wrap here 810 | cp #f6 ;#100 - 0a 811 | jr z,kdirskip2 812 | 813 | inc a 814 | seqScrReprint 815 | ld (FirstLineMS),a 816 | call printSeqScr0 817 | jr kdirskip2 818 | 819 | kleft 820 | ld a,(AlphaFlag) ;check for Alpha mode 821 | or a 822 | jr z,_noalpha 823 | ld a,(FirstLineMS) ;if Alpha mode is set, scroll 1 page (10 lines) 824 | sub #a 825 | jr pagescroll0 826 | 827 | _noalpha 828 | call delCsr 829 | ld a,(CsrPos) 830 | sub 1 831 | jr nc,kdirskip 832 | ;ld a,#4f 833 | ld a,7 834 | ld (OldCsrPos),a 835 | jp kuskip+3 836 | 837 | 838 | kdirskip 839 | ld (CsrPos),a 840 | kdirskip2 841 | call printCsr 842 | kdirskip3 843 | jp waitForKeyRelease 844 | ;ret 845 | 846 | kdir ;determine which direction key has been pressed 847 | rra 848 | jr nc,_kp 849 | inc d 850 | jp kdir 851 | _kp 852 | ld h,HIGH(kjumptab) ;set hi byte of jump table pointer 853 | kdirswitch equ $+1 ;switch for changing the response to keypress according to ptn type 854 | ld a,LOW(kjumptab) 855 | add a,d ;add D*2 856 | add a,d 857 | ld l,a ;set lo byte of jump table pointer 858 | ld e,(hl) ;get jump value into DE 859 | inc l 860 | ld d,(hl) 861 | ex de,hl ;swap jump value into HL 862 | 863 | jp (hl) ;and jump 864 | 865 | 866 | ;************************************************************************************ 867 | keyhand ;the main keyhandler 868 | 869 | ld a,KBD_GROUP_DIRPAD ;group dirpad 870 | out (kbd),a 871 | IF MODEL != TI82 872 | nop 873 | nop 874 | ENDIF 875 | ld e,#ff 876 | ld d,0 877 | in a,(kbd) 878 | cp e 879 | jr nz,kdir 880 | 881 | ld a,KBD_GROUP_ENTER ;group ENTER/+/-/*/div/^/CLEAR 882 | out (kbd),a 883 | ;nop 884 | ;nop 885 | key_delay 886 | in a,(kbd) 887 | rra ;ENTER 888 | jp nc,kenter 889 | rra 890 | jp nc,kplus ;+ 891 | rra 892 | jp nc,kminus ;- 893 | rra 894 | jp nc,kmult ;* 895 | rra 896 | jp nc,kdiv ;/ 897 | rra 898 | jp nc,kpot ;^ 899 | rra 900 | jp nc,kclear ;CLEAR 901 | 902 | ld a,KBD_GROUP_MINUS ;group (-)/3/6/9/)/G/VARS 903 | out (kbd),a 904 | ;nop 905 | ;nop 906 | key_delay 907 | in a,(kbd) 908 | rra 909 | jp nc,kneg 910 | rra 911 | jp nc,k3 912 | rra 913 | jp nc,k6 914 | rra 915 | jp nc,k9 916 | rra 917 | jp nc,kcbracket 918 | rra 919 | jp nc,kG 920 | rra 921 | jp nc,kvars 922 | 923 | ld a,KBD_GROUP_DOT ;group ./2/5/8/(/COS/PRGM/STAT 924 | out (kbd),a 925 | ;nop 926 | ;nop 927 | key_delay 928 | in a,(kbd) 929 | rra 930 | jp nc,kdot 931 | rra 932 | jp nc,k2 933 | rra 934 | jp nc,k5 935 | rra 936 | jp nc,k8 937 | rra 938 | jp nc,kobracket 939 | rra 940 | jp nc,kF 941 | rra 942 | jp nc,kC 943 | rra 944 | jp nc,kstat 945 | 946 | ld a,KBD_GROUP_ZERO ;group 0/1/4/7/'/SIN/APPS/XTθn 947 | out (kbd),a 948 | ;nop 949 | ;nop 950 | key_delay 951 | in a,(kbd) 952 | rra 953 | jp nc,k0 954 | rra 955 | jp nc,k1 956 | rra 957 | jp nc,k4 958 | rra 959 | jp nc,k7 960 | rra 961 | jp nc,kcomma 962 | rra 963 | jp nc,kE 964 | rra 965 | jp nc,kB 966 | rra 967 | jp nc,kxto 968 | 969 | ld a,KBD_GROUP_ALPHA ;group ALPHA/MATH/X-1/X2/LOG/LN/STO 970 | out (kbd),a 971 | ;nop 972 | ;nop 973 | key_delay 974 | in a,(kbd) 975 | rla 976 | jr nc,kalpha 977 | rla 978 | jr nc,kA 979 | rla 980 | jr nc,kD 981 | rla 982 | jr nc,kxsq 983 | rla 984 | jr nc,klog 985 | rla 986 | jr nc,kln 987 | rla 988 | jr nc,ksto 989 | 990 | ld a,KBD_GROUP_GRAPH ;group GRAPH/TRACE/ZOOM/WINDOW/Y=/2nd/MODE/DEL 991 | out (kbd),a 992 | ;nop 993 | ;nop 994 | key_delay 995 | in a,(kbd) 996 | rra 997 | jp nc,kgraph 998 | rra 999 | jp nc,ktrace 1000 | rra 1001 | jp nc,kzoom 1002 | rra 1003 | jp nc,kwindow 1004 | rra 1005 | jp nc,kyeq 1006 | rra 1007 | jp nc,k2nd 1008 | rra 1009 | jp nc,kmode 1010 | rra 1011 | jp nc,kdel 1012 | 1013 | ld a,(AlphaFlag) ;check ALPHA mode 1014 | or a 1015 | ret z ;exit keyhandler if not set (ignoring ON key) 1016 | 1017 | in a,(kon) ;check ON key 1018 | and %00001000 1019 | jp z,exit 1020 | ret ; 1021 | 1022 | 1023 | ;************************************************************************************ 1024 | kalpha 1025 | setXYat #28, #88 1026 | 1027 | ld a,(AlphaFlag) 1028 | xor #a0 1029 | ld (AlphaFlag),a ;set AlphaFlag 1030 | ld (LastKey),a ;set LastKey 1031 | 1032 | or a 1033 | jr z,_skip 1034 | 1035 | call printCharR ;print Alpha mode marker 1036 | _skip0 1037 | jp waitForKeyRelease 1038 | ;ret 1039 | 1040 | _skip 1041 | call clearPrintBuf ;clear print buffer 1042 | call printBuf ;remove Alpha mode marker from screen 1043 | jr _skip0 1044 | 1045 | kA 1046 | ld a,#0a 1047 | jp kHexInp 1048 | kD 1049 | ld a,#0d 1050 | jp kHexInp 1051 | 1052 | kxsq ;set loop point 1053 | ld hl,looprow 1054 | ld de,#2b8e 1055 | jr kBSet 1056 | 1057 | klog 1058 | ret 1059 | kln ;set BS 1060 | ld hl,CPS 1061 | ld de,#2b9a 1062 | jr kBSet 1063 | 1064 | ksto ;set BE 1065 | ld hl,CPE 1066 | ld de,#2ba0 1067 | 1068 | kBSet 1069 | call setXY 1070 | 1071 | ld a,(AlphaFlag) 1072 | or a 1073 | jr nz,kSetBFull ;if ALPHA mode is set, do a regular set BT 1074 | 1075 | kSetBlock 1076 | ld a,(CScrType) ;check screen type 1077 | or a 1078 | ret nz ;for now, ignore keypress if not on main screen TODO: implement alternative for ptn screens 1079 | 1080 | ld a,(FirstLineMS) ;calculate current line 1081 | ld b,a 1082 | ld a,(CsrPos) 1083 | rra ;on-screen row# = (CsrPos/8 AND %00001111) 1084 | rra 1085 | rra 1086 | and #f 1087 | add a,b ;absolute row# in sequence = first on-screen row# + current on-screen row# 1088 | ld (hl),a 1089 | 1090 | call printChars 1091 | exitthis 1092 | jp waitForKeyRelease 1093 | 1094 | kSetBFull 1095 | ld a,2 ;set InputType to signal 2-digit hex input 1096 | ld (InputType),a 1097 | ;ld hl,CPT 1098 | ld (iUpdatePos),hl ;set position in memory to update 1099 | ex de,hl 1100 | ld (iPrintPos),hl ;set print position 1101 | 1102 | call clearPrintBuf 1103 | call printBuf 1104 | 1105 | ld a,(CScrType) ;check what type of cursor to delete 1106 | cp 2 1107 | jp nz,delCsr 1108 | jp delCsr2 1109 | ;***** 1110 | kgraph ;set current Octave 1111 | 1112 | ld a,(CScrType) ;check screen type 1113 | dec a 1114 | ret nz ;if not on a ptn screen, ignore keypress 1115 | ld a,1 1116 | ld (InputType),a 1117 | 1118 | setXYat #23, #88 1119 | call clearPrintBuf 1120 | call printBuf 1121 | 1122 | call delCsr ;temporarily disable cursor 1123 | jp waitForKeyRelease 1124 | 1125 | ktrace 1126 | ld a,(AlphaFlag) 1127 | or a 1128 | jr nz,setUsrDrumHi 1129 | 1130 | ld hl,speed 1131 | setXYat #2b, #94 1132 | jp kSetBFull 1133 | 1134 | setUsrDrumHi 1135 | ld hl,usrDrum+1 1136 | setXYat #2a, #a6 1137 | ld a,4 1138 | jp kSetBFull+2 1139 | ;jp kSetBFull 1140 | 1141 | ; setUsrDrumLo ;TODO: dead code? 1142 | ; ld hl,usrDrum 1143 | ; setXYat #2b, a6 1144 | ; jp kSetBFull 1145 | 1146 | kzoom 1147 | ret 1148 | kwindow ;delete save slot / clear current tune 1149 | 1150 | ld a,(PlayerFlag) ;check if player is running - actually unnecessary, should be save to save while player is running 1151 | or a 1152 | ret nz ;if it is, ignore command 1153 | 1154 | ld a,(AlphaFlag) ;check alpha flag 1155 | or a 1156 | jr z,_zap 1157 | call delSlot 1158 | 1159 | jp waitForKeyRelease 1160 | ;jp nz,delSlot ;if Alpha mode is active, delete save slot 1161 | ;else, clear current tune 1162 | _zap 1163 | ld_de_TwoChars CHAR_C, CHAR_A ;print "CA" message 1164 | call printMsg 1165 | call confirmAction 1166 | jp c,exitthis 1167 | 1168 | pop hl 1169 | call zap 1170 | 1171 | jp reinit0 1172 | 1173 | kyeq ;load 1174 | ld a,(PlayerFlag) ;check if player is running - actually unnecessary, should be save to save while player is running 1175 | or a 1176 | ret nz ;if it is, ignore command 1177 | ld_de_TwoChars CHAR_L, CHAR_D ;LD message 1178 | ld a,(AlphaFlag) 1179 | ld iyh,a 1180 | or a 1181 | jr z,_skip 1182 | ld_de_TwoChars CHAR_S, CHAR_A ;SA message 1183 | _skip 1184 | call printMsg 1185 | call stateSelect 1186 | call confirmAction 1187 | jp c,exitthis 1188 | 1189 | ;ld a,(AlphaFlag) 1190 | ld a,iyh 1191 | or a 1192 | jp nz,save 1193 | 1194 | pop hl ;pop return address from stack 1195 | call load ;load song 1196 | 1197 | ld a,(StateSelect) 1198 | ex af,af' 1199 | jp reinit ;reinit HT2 1200 | 1201 | k2nd 1202 | ld a,(CScrType) ;check if we're on a pattern screen 1203 | or a 1204 | jr nz,_retPtnS 1205 | call clrS ;clear screen 1206 | ld a,(CsrPos) ;determine whether to print normal or fx pattern 1207 | ld (OldCsrPos),a 1208 | and %00000110 1209 | cp 6 1210 | jp nz,printPtnScr 1211 | jp printFxScr 1212 | 1213 | _retPtnS 1214 | call printSeqScr 1215 | call initSeqCsr 1216 | jp waitForKeyRelease 1217 | ;ret 1218 | kmode ;switch AutoInc/RowPlay mode 1219 | ld a,(AlphaFlag) 1220 | or a 1221 | jr nz,_toggleRP 1222 | 1223 | setXYat #29, #ac 1224 | 1225 | ld a,(AutoInc) 1226 | xor 1 1227 | ld (AutoInc),a 1228 | 1229 | xor 1 1230 | ld e,a 1231 | ld d,CHAR_A 1232 | 1233 | call printDE 1234 | 1235 | jp waitForKeyRelease 1236 | 1237 | _toggleRP 1238 | setXYat #2a, #ac 1239 | 1240 | ld a,(RowPlay) 1241 | cpl 1242 | ld (RowPlay),a 1243 | 1244 | or a 1245 | jr z,_skipx 1246 | call clearPrintBuf 1247 | ld a,CHAR_P 1248 | call printCharLNC 1249 | jp waitForKeyRelease 1250 | 1251 | _skipx 1252 | call clearPrintBuf ;clear print buffer 1253 | call printBuf 1254 | jp waitForKeyRelease 1255 | 1256 | kdel 1257 | ret 1258 | k0 1259 | xor a 1260 | jp kHexInp 1261 | k1 1262 | ld a,1 1263 | jp kHexInp 1264 | k4 1265 | ld a,4 1266 | jp kHexInp 1267 | k7 1268 | ld a,7 1269 | jp kHexInp 1270 | 1271 | kcomma ;mute ch1 1272 | ld a,(AlphaFlag) 1273 | or a 1274 | jr nz,_unmuteAll 1275 | ld a,(MuteState) ;toggle flag bit 0 1276 | xor 1 1277 | ld (MuteState),a 1278 | ld a,(mute1) ;toggle mute switch 1279 | ;xor #28 1280 | xor #8 1281 | ld (mute1),a 1282 | call printMute12 1283 | jp waitForKeyRelease 1284 | 1285 | _unmuteAll 1286 | xor a 1287 | ld (MuteState),a 1288 | ld a,#9f 1289 | ld (mute1),a 1290 | ld (mute2),a 1291 | ld (mute3),a 1292 | ld a,#d2 ;jp nc = #d2, jp = #c3 1293 | ;ld (mute1),a 1294 | ld (muteD),a 1295 | call printMute12 1296 | call printMute3D 1297 | jp waitForKeyRelease 1298 | 1299 | 1300 | kE 1301 | ld a,#0e 1302 | jp kHexInp 1303 | 1304 | kB 1305 | ld a,#0b 1306 | jp kHexInp 1307 | 1308 | kxto ;transpose 1309 | ld a,(CScrType) 1310 | dec a ;checking if we're currently on a note pattern screen 1311 | jp nz,waitForKeyRelease 1312 | 1313 | call findCurrPtn ;pattern pointer now in DE 1314 | 1315 | ld b,#10 ;16 notes to transpose 1316 | 1317 | ld a,(AlphaFlag) 1318 | or a 1319 | jr nz,_transposeDown 1320 | 1321 | _transposeUp 1322 | ld a,(de) 1323 | or a ;check for rest (#00) 1324 | jr z,_notranspose 1325 | inc a ;transpose up by 1 halftone 1326 | cp #55 ;check for upper limit (#00) 1327 | jr nz,_notranspose 1328 | xor a ;replace with if upper limit crossed 1329 | 1330 | _notranspose 1331 | ld (de),a 1332 | inc de 1333 | djnz _transposeUp 1334 | 1335 | _done 1336 | jp printPtnScrBasic 1337 | 1338 | 1339 | _transposeDown 1340 | ld a,(de) 1341 | dec a 1342 | cp #ff 1343 | jr nz,_notranspose2 1344 | xor a 1345 | 1346 | _notranspose2 1347 | ld (de),a 1348 | inc de 1349 | djnz _transposeDown 1350 | 1351 | jp printPtnScrBasic 1352 | 1353 | 1354 | ;ret 1355 | kdot 1356 | ret 1357 | k2 1358 | ld a,2 1359 | jp kHexInp 1360 | k5 1361 | ld a,5 1362 | jp kHexInp 1363 | k8 1364 | ld a,8 1365 | jp kHexInp 1366 | 1367 | kobracket 1368 | ld a,(AlphaFlag) 1369 | or a 1370 | jr nz,kMuteD 1371 | 1372 | ld a,(MuteState) ;toggle flag bit 1 1373 | xor 2 1374 | ld (MuteState),a 1375 | ld a,(mute2) 1376 | xor #8 ;toggle between jr nc and unconditional jr 1377 | ld (mute2),a 1378 | call printMute12 1379 | jp waitForKeyRelease 1380 | 1381 | kMuteD 1382 | ld a,(MuteState) ;toggle flag bit 7 1383 | xor #80 1384 | ld (MuteState),a 1385 | ld a,(muteD) 1386 | xor #11 1387 | ld (muteD),a 1388 | call printMute3D 1389 | jp waitForKeyRelease 1390 | 1391 | 1392 | 1393 | kF 1394 | ld a,#0f 1395 | jp kHexInp 1396 | kC 1397 | ld a,#0c 1398 | jp kHexInp 1399 | kstat 1400 | kneg ;play from current row 1401 | ld a,(PlayerFlag) 1402 | or a 1403 | jp nz,waitForKeyRelease 1404 | 1405 | ld a,(AlphaFlag) ;check AlphaFlag 1406 | or a 1407 | jr z,_skip0 1408 | ld a,#af ;if set, enable pattern looping 1409 | ld (ptnLoopSwitch),a 1410 | ld a,#e1 1411 | ld (fxb_pm_loop_switch),a 1412 | _skip0 1413 | ld (exitPlayerSP),sp ;store SP for exiting player 1414 | inc a ;set player flag, A=1 1415 | ld (PlayerFlag),a 1416 | 1417 | call printPlayModeIndicator 1418 | call waitForKeyRelease 1419 | 1420 | xor a 1421 | ld h,a 1422 | ld d,a 1423 | ld a,(CScrType) ;if on seq.screen 1424 | or a 1425 | ld a,(CsrPos) ;derive current sequence line from (CsrPos) 1426 | jr z,_skip 1427 | ld a,(OldCsrPos) ;else, derive it from (OldCsrPos) 1428 | _skip 1429 | call findCurrLineNoSeq ;find current line in sequence 1430 | ex de,hl ;get pointer into DE 1431 | 1432 | call initrp ;call player 1433 | jp exitplayer 1434 | 1435 | k3 1436 | ld a,3 1437 | jp kHexInp 1438 | k6 1439 | ld a,6 1440 | jp kHexInp 1441 | k9 1442 | ld a,#09 1443 | jp kHexInp 1444 | 1445 | kcbracket 1446 | ld a,(AlphaFlag) 1447 | or a 1448 | jr nz,_muteAll 1449 | ld a,(MuteState) ;toggle flag bit 6 1450 | xor #40 1451 | ld (MuteState),a 1452 | ld a,(mute3) ;toggle between sbc a,a and sub a 1453 | xor #8 1454 | ld (mute3),a 1455 | call printMute3D 1456 | jp waitForKeyRelease 1457 | 1458 | _muteAll 1459 | ld a,%11000011 1460 | ld (MuteState),a 1461 | ld a,#97 1462 | ld (mute1),a 1463 | ld (mute2),a 1464 | ld (mute3),a 1465 | ld a,#c3 ;jp nc = #d2, jp = #c3 1466 | ;ld (mute1),a 1467 | ld (muteD),a 1468 | call printMute12 1469 | call printMute3D 1470 | jp waitForKeyRelease 1471 | 1472 | 1473 | kG 1474 | ld a,(CScrType) ;check screen type 1475 | cp 1 1476 | ret nz ;ignore keypress if not on a note ptn screen 1477 | ld b,#10 1478 | jp kHexPtn 1479 | kvars 1480 | ret 1481 | 1482 | kminus 1483 | ld a,(CScrType) ;detect current screen type 1484 | or a 1485 | jp nz,waitForKeyRelease ;and exit if not on sequence screen 1486 | 1487 | call findCurrLine ;get pointer to current line into HL 1488 | 1489 | push hl 1490 | xor a ;clear carry 1491 | ld de,ptn00-5 ;point DE to end of ptn sequence - 5 1492 | ex de,hl 1493 | sbc hl,de ;end - 5 - current line = copy length 1494 | ld b,h ;block length now in BC 1495 | ld c,l 1496 | pop hl 1497 | 1498 | ld a,(AlphaFlag) ;check if we're inserting or deleting 1499 | or a 1500 | jr nz,_deleteRow 1501 | 1502 | ld hl,ptn00-6 ;source = end of sequence - 4 1503 | ld de,ptn00-2 ;dest = end of sequence 1504 | lddr ;copy stuff 1505 | 1506 | _reprint 1507 | call printSeqScr0 1508 | call printCsr 1509 | jp waitForKeyRelease 1510 | 1511 | _deleteRow 1512 | ld d,h ;dest now in DE 1513 | ld e,l 1514 | inc hl ;source = dest + 4 1515 | inc hl 1516 | inc hl 1517 | inc hl 1518 | ldir ;copy stuff 1519 | 1520 | ld b,4 ;clean up sequence end 1521 | ld hl,ptn00-5 1522 | ld a,#ff 1523 | _lp 1524 | ld (hl),a 1525 | inc hl 1526 | djnz _lp 1527 | jumpReprintX 1528 | jp reprintX 1529 | 1530 | 1531 | kplus ;insert next free pattern value at cursor 1532 | ld a,(CScrType) ;detect current screen type 1533 | or a 1534 | jp nz,waitForKeyRelease ;and exit if not on sequence screen 1535 | 1536 | call getSeqOffset ;get source pattern # and save it for later use 1537 | ld (SourcePtn),a 1538 | 1539 | ld a,(CsrPos) 1540 | and %00000110 1541 | cp 6 1542 | jr z,insertFxPtn 1543 | 1544 | xor a 1545 | _chklp 1546 | call findNextUnused 1547 | jr z,noFreePtn 1548 | push af 1549 | call isPtnFree 1550 | jr z,freeFound 1551 | pop af 1552 | inc a 1553 | cp #80 ;check if all patterns have been searched 1554 | jr nz,_chklp 1555 | 1556 | noFreePtn ;handling error if no free ptns found 1557 | ld a,7 1558 | jp errorHand 1559 | 1560 | freeFound 1561 | call getSeqOffset 1562 | pop af 1563 | ld (hl),a 1564 | 1565 | ld a,(AlphaFlag) ;check for Alpha mode 1566 | or a 1567 | jr z,_return 1568 | 1569 | ld a,(SourcePtn) ;if in Alpha mode, copy source pattern to new pattern 1570 | inc a 1571 | jr z,jumpReprintX ;don't copy if source pattern was #ff 1572 | 1573 | ld a,(CsrPos) 1574 | and %00000110 1575 | cp 6 1576 | ld a,(hl) 1577 | jr z,_copyfx 1578 | 1579 | call findPtn ;find the current pattern in memory - pointer is now in DE 1580 | push de ;preserve pointer to it 1581 | 1582 | ld a,(SourcePtn) 1583 | call findPtn ;find source pattern in memory 1584 | ex de,hl ;put pointer to it in HL 1585 | pop de ;retrieve source pointer 1586 | 1587 | ld bc,#10 ;copy pattern 1588 | _copy 1589 | ldir 1590 | 1591 | _return 1592 | jr jumpReprintX 1593 | 1594 | 1595 | _copyfx 1596 | ld hl,fxptntab 1597 | call findCurrFxPtn 1598 | push de 1599 | 1600 | ld a,(SourcePtn) 1601 | ld hl,fxptntab 1602 | call findCurrFxPtn 1603 | ex de,hl 1604 | pop de 1605 | 1606 | ld bc,#20 1607 | jr _copy 1608 | 1609 | 1610 | insertFxPtn 1611 | xor a 1612 | _chklp 1613 | call findNextUnusedFX 1614 | jr z,noFreePtn 1615 | push af 1616 | call isFxPtnFree 1617 | jr z,freeFound 1618 | pop af 1619 | inc a 1620 | cp #40 1621 | jr nz,_chklp 1622 | 1623 | 1624 | kmult ;copy/del block 1625 | ld a,(CScrType) ;detect current screen type 1626 | or a 1627 | jp nz,waitForKeyRelease ;and exit if not on sequence screen 1628 | 1629 | ld a,(AlphaFlag) ;check Alpha mode 1630 | or a 1631 | jr z,insertBlk 1632 | 1633 | _deleteBlock 1634 | ld a,(CPS) ;verify that Block End >= Block Start 1635 | ld b,a 1636 | ld a,(CPE) 1637 | sub b 1638 | ld l,a ;save block length (lines) - 1 in L 1639 | ld a,1 1640 | jp c,errorHand ;output error if BS/BE invalid 1641 | 1642 | ld h,0 ;calculate block length in memory 1643 | inc hl ;adjust length (always 1 line more than calculated) 1644 | add hl,hl 1645 | add hl,hl 1646 | 1647 | push hl ;block length now in HL 1648 | 1649 | ld bc,ptns 1650 | ld a,(CPS) ;target = (CPS)*4 + ptns 1651 | ld h,0 1652 | ld l,a 1653 | add hl,hl 1654 | add hl,hl 1655 | add hl,bc 1656 | ex de,hl ;target now in DE 1657 | 1658 | ld a,(CPE) ;source = (CPE+1)*4 + ptns 1659 | inc a 1660 | ld h,0 1661 | ld l,a 1662 | add hl,hl 1663 | add hl,hl 1664 | add hl,bc ;source now in HL 1665 | 1666 | push hl 1667 | push de 1668 | ex de,hl 1669 | 1670 | ld hl,ptn00-1 ;copy length = ptns.end - source +1? 1671 | xor a 1672 | sbc hl,de 1673 | ld b,h 1674 | ld c,l 1675 | 1676 | pop de 1677 | pop hl 1678 | ldir 1679 | 1680 | pop bc ;retrieve block length into bc 1681 | ld hl,ptn00-2 1682 | 1683 | _lp2 1684 | ld a,#ff 1685 | ld (hl),a 1686 | dec hl 1687 | dec bc 1688 | ld a,b 1689 | or c 1690 | jr nz,_lp2 1691 | 1692 | jp reprintX 1693 | 1694 | 1695 | 1696 | insertBlk 1697 | ld a,(CPS) ;verify that Block End >= Block Start 1698 | exx 1699 | ld d,a 1700 | exx 1701 | ld b,a 1702 | ld a,(CPE) 1703 | exx 1704 | ld e,a 1705 | exx 1706 | sub b 1707 | ld b,a ;save block length - 1 in B 1708 | ld a,1 1709 | jp c,errorHand ;and output error if it isn't 1710 | 1711 | call getCurrLineNo 1712 | ld c,a 1713 | 1714 | inc a ;check that curr line + block length <= #ff 1715 | add a,b 1716 | ld a,8 1717 | jp c,errorHand 1718 | 1719 | ld a,(CPS) 1720 | sub c 1721 | jr nc,_insertBefore ;if BS >= curr line, we're inserting before the selection 1722 | ld a,(CPE) 1723 | sub c 1724 | jr c,_insertAfter ;if curr line > BE, we're inserting after the selection 1725 | ld a,1 ;else, curr line is within selection -> output error 1726 | jp errorHand 1727 | 1728 | 1729 | _insertBefore 1730 | push bc 1731 | exx 1732 | pop bc 1733 | inc b 1734 | ld a,d 1735 | add a,b 1736 | ld d,a 1737 | ld a,e 1738 | add a,b 1739 | ld e,a 1740 | exx 1741 | 1742 | 1743 | _insertAfter 1744 | ld a,(AlphaFlag) ;check Alpha mode 1745 | or a 1746 | jr nz,_paste ;and skip pre-shifting data if in Alpha mode 1747 | call calculateCopyParams ;calculate Block start, length, current line # 1748 | 1749 | ld hl,ptn00-2 ;calculate shift block params 1750 | or a ;clear carry 1751 | sbc hl,bc ;source now in HL 1752 | push hl 1753 | 1754 | call findCurrLine ;current line start now in HL 1755 | 1756 | ex de,hl ;current line start now in DE 1757 | 1758 | pop hl ;retrieve source pointer 1759 | push hl 1760 | 1761 | xor a 1762 | sbc hl,de ;copy block length = source - current line start + 1 1763 | inc hl 1764 | ld b,h 1765 | ld c,l ;copy block length now in BC 1766 | 1767 | pop hl ;retrieve source pointer 1768 | ld de,ptn00-2 ;set dest. pointer 1769 | 1770 | lddr ;shift block 1771 | 1772 | _paste 1773 | call calculateCopyParams ;calculate Block start, length, current line # 1774 | push bc 1775 | 1776 | ld l,a ;calculate copy destination 1777 | ld h,0 1778 | add hl,hl 1779 | add hl,hl ;copy destination - base offset now in HL 1780 | ld bc,ptns 1781 | add hl,bc 1782 | ex de,hl ;copy destination now in DE 1783 | 1784 | add hl,bc ;block start now in HL 1785 | pop bc 1786 | ldir 1787 | 1788 | jp reprintX 1789 | 1790 | 1791 | kdiv ;deleting blocks 1792 | ld a,(CScrType) 1793 | or a 1794 | jp nz,waitForKeyRelease 1795 | 1796 | ld a,(AlphaFlag) ;check for Alpha mode 1797 | or a 1798 | jp nz,insertBlk 1799 | jp waitForKeyRelease ;do nothing if Alpha not active 1800 | 1801 | 1802 | kpot 1803 | ret 1804 | 1805 | kclear ;toggle synth (hold) mode 1806 | ld a,(SynthMode) 1807 | cpl 1808 | ld (SynthMode),a 1809 | or a 1810 | ld a,#1d ;disable 1811 | jr z,_set 1812 | 1813 | ld a,#3c ;enable 1814 | _set 1815 | ld (timerHold),a 1816 | call printPlayModeIndicator 1817 | jp waitForKeyRelease 1818 | 1819 | 1820 | 1821 | kenter 1822 | ld a,(PlayerFlag) ;check if player is running 1823 | or a 1824 | jr nz,exitplayer 1825 | 1826 | ld (exitPlayerSP),sp ;store SP for exiting player 1827 | inc a ;set player flag, A=1 1828 | ld (PlayerFlag),a 1829 | 1830 | call printPlayModeIndicator 1831 | call mplay ;call the music player 1832 | 1833 | exitplayer 1834 | exitPlayerSP equ $+1 1835 | ld sp,0 ;restore stack 1836 | xor a ;reset player flag 1837 | ld (PlayerFlag),a 1838 | ld a,lp_off ;turn off sound 1839 | out (link),a 1840 | ld a,#ba ;disable pattern looping 1841 | ld (ptnLoopSwitch),a 1842 | ld a,#f1 1843 | ld (fxb_pm_loop_switch),a 1844 | 1845 | call printPlayModeIndicator 1846 | jp waitForKeyRelease 1847 | ;ret ;return to keyhandler 1848 | -------------------------------------------------------------------------------- /main.asm: -------------------------------------------------------------------------------- 1 | ;******************************************************************************* 2 | ;HOUSTONTRACKER 2.30.00 3 | ;by utz * irrlichtproject.de/houston 4 | ;******************************************************************************* 5 | 6 | ;******************************************************************************* 7 | ;OS/shell settings 8 | ;******************************************************************************* 9 | 10 | TI82 EQU 1 ;pass model number to pasmo 11 | TI83 EQU 2 ;with --equ MODEL= 12 | TI8X EQU 3 13 | TI8P EQU 4 14 | TI8XS EQU 5 15 | 16 | IF MODEL = TI82 17 | include "include/ti82.inc" 18 | ENDIF 19 | 20 | IF MODEL = TI8P 21 | include "include/ti82parcus.inc" 22 | ENDIF 23 | 24 | IF MODEL = TI83 25 | include "include/ti83.inc" 26 | ENDIF 27 | 28 | IF MODEL = TI8X 29 | include "include/ti8xp.inc" 30 | ENDIF 31 | 32 | IF MODEL = TI8XS 33 | include "include/ti8xs.inc" 34 | ENDIF 35 | 36 | db "HT 2.30", 0 ;in-shell title 37 | 38 | ;******************************************************************************* 39 | ;scratch pad index and additional equates 40 | ;******************************************************************************* 41 | 42 | include "include/scratchpad.inc" 43 | 44 | ;******************************************************************************* 45 | ;main() init point 46 | ;******************************************************************************* 47 | 48 | begin 49 | include "init.asm" ;initialize stuff 50 | 51 | call waitForKeyRelease ;make sure no key is pressed before entering keyhandler 52 | 53 | 54 | ;The main loop. Yes, it's very simple ;) 55 | ;However, there's some inception going on under the hood. Ok, so the main loop calls keyhand. Now, when 56 | ;keyhand detects a keypress indicating to start the player, then keyhand will call the player. The 57 | ;player then in turn calls keyhand! Now there is keyhand running on top of keyhand. keyhand modifies 58 | ;itself in this situation, and disables certain actions like exiting the program. This is to ensure 59 | ;that this "inception" is running in a stack-safe manner. 60 | ;There are however additional safeguards against stack corruption, see section "shutdown code". 61 | 62 | mainlp 63 | call keyhand 64 | 65 | jp mainlp 66 | 67 | ;******************************************************************************* 68 | ;keyhandler 69 | ;******************************************************************************* 70 | 71 | include "keyhand.asm" 72 | 73 | ;******************************************************************************* 74 | ;shutdown code 75 | ;******************************************************************************* 76 | exit ;exit HT2 77 | ld a,#d2 ;reset mute switches (#30 = jr nc,..) 78 | ;ld (mute1),a 79 | ld (muteD),a 80 | ld a,#9f ;#9f = sbc a,a 81 | ld (mute1),a 82 | ld (mute2),a 83 | ld (mute3),a 84 | 85 | ld a,lp_on ;switch link port lines high again 86 | out (link),a 87 | 88 | 89 | exitSP equ $+1 ;reset stack 90 | ld sp,0 91 | pop ix ;restore index registers 92 | pop iy 93 | 94 | ei ;done automatically by CrASH 95 | ret ;and byebye 96 | 97 | ;******************************************************************************* 98 | ;various utility subroutines 99 | ;******************************************************************************* 100 | 101 | include "util.asm" 102 | 103 | ;******************************************************************************* 104 | ;graphics driver, print routines 105 | ;******************************************************************************* 106 | 107 | include "gfx.asm" 108 | 109 | ;******************************************************************************* 110 | ;load/save routines, compression, savestate management 111 | ;******************************************************************************* 112 | 113 | include "mem.asm" 114 | 115 | ;******************************************************************************* 116 | ;various tables and includes 117 | ;******************************************************************************* 118 | 119 | include "data.asm" 120 | 121 | ;******************************************************************************* 122 | ;music driver 123 | ;******************************************************************************* 124 | 125 | include "player.asm" 126 | 127 | ;******************************************************************************* 128 | ;work area 129 | ;******************************************************************************* 130 | 131 | musicData ;initialize an empty song on first run 132 | 133 | speed 134 | db #10 ;speed 135 | usrDrum 136 | dw #0 ;usr drum pointer 137 | looprow 138 | db 0 ;loop point (row#) 139 | 140 | ptns ;the pattern matrix 141 | ds 256*4,#ff ;1024+1 #ff bytes 142 | db #ff 143 | 144 | ptn00 ;the note patterns 145 | ds 16*128 ;128*16 #00 bytes 146 | 147 | fxptn00 ;the fx patterns 148 | ds 32*64 ;64*32 #00 bytes 149 | 150 | musicEnd equ $ ;=savestate LUT 151 | 152 | ;******************************************************************************* 153 | ;savestates 154 | ;******************************************************************************* 155 | 156 | db 'XSAVE' ;savestate block header 157 | savestateLUT ;32 byte save state lookup table 158 | dw savestates ;DEBUG 159 | dw firstend-1 ;DEBUG 160 | ds 28 161 | 162 | savestates ;compressed savestates 163 | include "teststate.asm" 164 | 165 | firstend equ $ ;debug symbol 166 | 167 | ;******************************************************************************* 168 | ;version signature 169 | ;******************************************************************************* 170 | 171 | org mem_end-2 172 | version 173 | db 1,2 ;savestate format version 174 | -------------------------------------------------------------------------------- /mem.asm: -------------------------------------------------------------------------------- 1 | ;memory related subroutines 2 | ;************************************************************************************ 3 | stateSelect ;prompt user to select a savestate (slot) number 4 | ld a,(CScrType) 5 | cp 2 6 | 7 | call z,delCsr2 8 | jr _skip 9 | call delCsr 10 | _skip 11 | jp inputSlotNr 12 | 13 | ;************************************************************************************ 14 | delSlot ;delete a save slot 15 | 16 | ld_de_TwoChars CHAR_D, CHAR_S ;print "DS" message 17 | call printMsg 18 | call stateSelect 19 | call confirmAction 20 | ret c 21 | 22 | delSlotNoConfirm ;delete slot without asking for confirmation 23 | ld a,(StateSelect) ;read save slot number 24 | add a,a ;calculate offset in savestate LUT 25 | add a,a 26 | ld e,a 27 | ld d,0 28 | ld hl,savestateLUT ;calculate pointer to LUT entry 29 | add hl,de 30 | 31 | ld e,(hl) ;load lo byte of delslot.start 32 | inc hl 33 | ld a,(hl) ;check if savestate is empty 34 | or a 35 | ret z ;and exit if that's the case 36 | 37 | ld d,a ;delslot.start now in DE 38 | 39 | dec hl ;preserve LUT pointer on stack 40 | push hl 41 | inc hl 42 | 43 | inc hl 44 | ld c,(hl) 45 | inc hl 46 | ld b,(hl) 47 | inc bc ;delslot.end+1 now in BC 48 | push bc 49 | 50 | xor a 51 | ld hl,mem_end-3 52 | sbc hl,bc 53 | 54 | ld b,h 55 | ld c,l ;remaining block length now in BC 56 | pop hl ;delslot.end+1 in in HL 57 | 58 | push de 59 | push hl 60 | 61 | ldir ;copy remaining block to new location 62 | 63 | delUpdateLUT 64 | pop hl 65 | dec hl ;delslot.end 66 | pop de ;delslot.start 67 | 68 | xor a 69 | sbc hl,de ;delslot.length now in HL 70 | 71 | pop bc ;retrieve LUT pointer 72 | ld (bc),a ;clear LUT entry 73 | inc bc 74 | ld (bc),a 75 | inc bc 76 | ld (bc),a 77 | inc bc 78 | ld (bc),a 79 | 80 | ld (_oldSP),sp ;preserve stack pointer 81 | ld sp,hl ;delslot.length now in SP 82 | ld hl,savestateLUT 83 | ld b,d ;delslot.start now in BC 84 | ld c,e 85 | exx 86 | ld b,#10 ;updating 16 word-length entries (8 long) 87 | 88 | _lp 89 | exx 90 | ld e,(hl) ;read entry from savestate LUT 91 | inc hl 92 | ld d,(hl) 93 | 94 | ex de,hl 95 | xor a 96 | sbc hl,bc ;check if entry < delslot.start (or entry == 0) 97 | ex de,hl 98 | 99 | jr c,_noupdate ;if so, move on to the next entry 100 | 101 | ex de,hl 102 | add hl,bc ;restore slot val 103 | sbc hl,sp ;subtract delslot.length from entry 104 | ex de,hl 105 | 106 | dec de 107 | ld (hl),d ;store updated slot val in LUT 108 | dec hl 109 | ld (hl),e 110 | inc hl 111 | 112 | _noupdate 113 | inc hl 114 | exx 115 | djnz _lp 116 | 117 | _oldSP equ $+1 ;restore stack pointer 118 | ld sp,0 119 | 120 | ;jp waitForKeyRelease 121 | ret 122 | 123 | ;************************************************************************************ 124 | zap ;delete song currently loaded in work area 125 | ld hl,#10 ;clear speed, usr drum, lp 126 | ld (musicData),hl 127 | ld l,0 128 | ld (musicData+2),hl 129 | 130 | ld hl,musicData+4 ;clearing sequence (writing 1025 #ff bytes) 131 | ld de,musicData+5 132 | ;ld bc,1024 133 | ld bc,1025 ;NEW 134 | ld a,#ff 135 | ld (hl),a 136 | ldir 137 | 138 | xor a ;clearing pattern area (writing 4096 #00 bytes) 139 | ld (hl),a 140 | ld bc,4095 141 | ldir 142 | 143 | jp resetFX0 144 | 145 | ;************************************************************************************ 146 | addressCompare ;compare two 16-bit values 147 | ;IN: val 1 in DE, val 2 in BC | OUT: higher val in BC 148 | 149 | ex af,af' 150 | inc a ;signal to save code that a savestate has been found 151 | ex af,af' 152 | 153 | ;dec hl 154 | ld e,(hl) 155 | inc de 156 | push hl 157 | 158 | ld h,b 159 | ld l,c 160 | 161 | xor a ;clear carry (should in theory be cleared by previous or d) 162 | sbc hl,de 163 | jr nc,_return ;if BC > DE, all is good 164 | 165 | ld b,d ;else, DE -> BC 166 | ld c,e 167 | 168 | _return 169 | pop hl 170 | ;inc hl ;pointer adjustment 171 | ret 172 | 173 | ;************************************************************************************ 174 | save ;save a compressed backup savestate of the current song 175 | 176 | call delSlotNoConfirm ;if savestate exists in the current slot, delete it 177 | 178 | _findMemLoc ;iterate through savestate LUT to find the next free memory location 179 | ld hl,savestateLUT+31 180 | ld bc,0 181 | 182 | xor a 183 | ex af,af' 184 | ;xor a 185 | exx 186 | ld b,8 187 | 188 | 189 | _findlp 190 | xor a 191 | exx 192 | ld d,(hl) ;read hi byte of slot.end 193 | or d ;if it's non-zero, this is an existing savestate 194 | dec hl 195 | 196 | call nz,addressCompare 197 | 198 | dec hl ;else, decrement pointer 199 | dec hl 200 | dec hl 201 | exx 202 | djnz _findlp ;and loop 203 | 204 | exx 205 | ld de,savestates ;if no existing save states are found, set MemLoc to start of savestate area 206 | 207 | ex af,af' 208 | or a ;A' holds # of savestates found TODO BUG: A=0 even though it shouldn't be, likewise BC=0 209 | jr z,_proceed 210 | 211 | ld d,b 212 | ld e,c 213 | 214 | _proceed 215 | ld a,(StateSelect) ;read selected state # 216 | add a,a 217 | add a,a 218 | ld c,a 219 | ld b,0 220 | ld hl,savestateLUT 221 | add hl,bc ;point to it in LUT 222 | ld (hl),e ;and write start address of the slot to be saved to LUT 223 | inc hl 224 | ld (hl),d 225 | 226 | inc hl 227 | ld (LUTpointer),hl ;preserve pointer address for writing slot.end value later on 228 | 229 | ;****** 230 | ;ld de,savestates ;DEBUG 231 | ;DE holds start address (target) 232 | ld hl,musicData 233 | ld bc,#04ff ;b=counter, c=bogus high value to obfuscate decrement by ldi 234 | 235 | _savevars 236 | ldi ;save global vars 237 | call chkMemEnd ;test for out of mem error 238 | djnz _savevars 239 | 240 | _saveseq ;save song sequence 241 | ld a,(hl) 242 | ldi ;save 1 byte 243 | call chkMemEnd ;test for out of mem error 244 | inc a ;check if last saved byte was #ff 245 | jr nz,_saveseq ;save next byte if it wasn't 246 | 247 | _saveptns 248 | ex de,hl ;now HL = store pointer 249 | ld de,ptn00 ;DE = read pointer 250 | 251 | _saveptnlp 252 | call chkLastPtn ;check if all ptns have been saved 253 | jr nz,_skip1 254 | ld a,#ff ;if yes, write an #ff byte 255 | ld (hl),a 256 | inc hl ;update pointers 257 | jr saveFX ;and continue with fx ptns 258 | 259 | _skip1 260 | ld a,#df ;assume that the following n patterns are empty 261 | ld (hl),a ;write #df byte 262 | ld c,#1f ;C = # of patterns to check, checking the following #20 patterns 263 | 264 | _isPtnEmpty ;check if current pattern is empty 265 | ld b,#10 ;check #10 rows 266 | push de 267 | _lp 268 | ld a,(de) ;check if byte == 0 269 | or a 270 | jr nz,_isRowEmpty ;if it isn't, continue with checking for empty rows 271 | inc de ;else, inc pointer 272 | djnz _lp ;and check next row 273 | 274 | pop de ;retrieve load pointer 275 | inc (hl) ;increment "empty ptns" counter - DOESN'T THIS HAVE TO BE inc (hl)??? (was inc hl) 276 | ;ATTN: SURE? 277 | 278 | push hl ;increment load pointer by #10 279 | ld hl,#10 280 | add hl,de 281 | ex de,hl 282 | pop hl 283 | 284 | dec c ;decrement "# of ptns to check" counter 285 | jr nz,_isPtnEmpty ;and check next ptn if done with all #20 ptns 286 | 287 | inc hl ;else, increment store pointer 288 | ex de,hl 289 | call chkMemEnd ;check for mem_end 290 | ex de,hl 291 | jr _saveptnlp ;and move on to the next ptn 292 | 293 | 294 | _isRowEmpty 295 | pop de ;retrieve load pointer 296 | 297 | ld a,(hl) ;NEW: check if e0 byte was previously written 298 | cp #e0 ;NEW: 299 | jr c,_skipxx ;NEW: 300 | inc hl ;NEW: and inc save pointer if necessary 301 | 302 | _skipxx 303 | ld a,#cf ;assume next row is empty 304 | ld (hl),a 305 | ld b,#10 ;check up to #10 rows 306 | _lp2 307 | ld a,(de) ;check if byte == 0 308 | or a 309 | jr nz,_rNotEmpty ;if byte != 0, row isn't empty 310 | 311 | inc (hl) ;else, increment "empty rows" counter 312 | inc de ;increment load pointer 313 | 314 | _exitlp 315 | djnz _lp2 ;and keep checking for empty rows if not all have been checked yet 316 | 317 | ld a,#cf ;NEW 20-09: unless end of pattern reached with non-empty row, inc write pointer 318 | cp (hl) 319 | jr z,_skipxxx 320 | inc hl 321 | _skipxxx 322 | jr _saveptnlp ;else, move on to the next ptn 323 | 324 | _rNotEmpty 325 | ld a,(hl) ;if row wasn't empty 326 | cp #d0 ;check if an "empty rows" or "empty ptns" counter was previously written 327 | jr c,_skipx 328 | inc hl ;increment store pointer if yes 329 | _skipx 330 | ex de,hl 331 | ldi ;copy 1 byte 332 | call chkMemEnd ;check for mem_end 333 | inc bc ;adjust counter 334 | ex de,hl 335 | ld a,#cf ;assume next row is empty 336 | ld (hl),a 337 | jr _exitlp ;and move on to the next row 338 | 339 | 340 | saveFX ;compress and save the fx patterns 341 | ld de,fxptn00 342 | ex de,hl ;now DE = store pointer and HL = read pointer again 343 | 344 | push hl ;check if all fx ptns are empty. 345 | ld bc,#800 ;check following 2048 bytes 346 | 347 | _clp 348 | ld a,(hl) 349 | or a 350 | jr nz,_cont 351 | inc hl 352 | dec bc 353 | ld a,b 354 | or c 355 | jr nz,_clp 356 | 357 | pop hl ;If all fx ptns were empty, write #ff byte and exit. 358 | cpl 359 | ld (de),a 360 | jp _success+1 361 | 362 | _cont 363 | pop hl 364 | ex af,af' 365 | ld a,#ff ;AF' = pattern counter 366 | ex af,af' 367 | 368 | _sfxlp 369 | ex af,af' 370 | inc a ;inc pattern counter 371 | cp #40 ;SHOULD BE cp #40? if it's #40 or bit 7 is set, we're done saving 372 | ;ret nc 373 | jp nc,_success 374 | ex af,af' 375 | 376 | _lookAhead ;check if the next ptn is empty (next 32B == 0) 377 | ld b,#20 378 | push hl ;preserve read pointer 379 | _lAlp 380 | ld a,(hl) ;check if bytes == 0 381 | or a 382 | inc hl 383 | jr nz,_fxNotEmpty ;if byte != 0, pattern isn't empty 384 | djnz _lAlp 385 | 386 | pop hl ;if pattern was empty, retrieve read pointer 387 | ld bc,#20 ;point to next pattern (add 32) 388 | add hl,bc 389 | jr _sfxlp ;repeat from start 390 | 391 | _fxNotEmpty 392 | pop hl 393 | push hl 394 | ld bc,#20 395 | add hl,bc 396 | _fxNElp 397 | ld a,(hl) ;check if remaining fx ptns (except the current one) are empty 398 | or a 399 | inc hl 400 | jr nz,_writeFxPtn ;if byte != 0 found, copy ptn normally 401 | 402 | ld a,h ;check if end of work area reached 403 | cp HIGH(musicEnd) 404 | jr nz,_fxNElp 405 | ld a,l 406 | cp LOW(musicEnd) 407 | jr nz,_fxNElp ;if not, keep parsing fx ptns 408 | 409 | ex af,af' ;if all remaining fx ptns were empty 410 | add a,#80 ;set bit 7 of the ptn counter 411 | ex af,af' 412 | 413 | _writeFxPtn 414 | ex af,af' 415 | ld (de),a ;write ptn # at store pointer 416 | ex af,af' 417 | pop hl ;retrieve load pointer 418 | inc de 419 | ;ld bc,#20 ;copying 32 bytes 420 | ld b,#20 421 | _writelp 422 | ldi ;transfer a byte 423 | call chkMemEnd ;check for mem_end 424 | ;ldi 425 | ;jr nz,_writelp 426 | djnz _writelp 427 | jr _sfxlp ;and on to the next pattern 428 | 429 | _success 430 | dec de 431 | ;ld a,(StateSelect) 432 | LUTpointer equ $+2 433 | ld (savestateLUT+2),de ;write end address to savestate LUT 434 | 435 | ld a,(StateSelect) 436 | call printSaveSlotIndicator 437 | 438 | xor a 439 | jp errorHand 440 | ;************************************************************************************ 441 | chkLastPtn ;check if all used note patterns have been saved 442 | ;OUT: Z if all used ptns have been saved, else NZ 443 | push de 444 | _lp 445 | ld a,d ;check if end of note ptn area reached 446 | cp HIGH(fxptn00) 447 | jr nz,_skip 448 | ld a,e 449 | cp LOW(fxptn00) 450 | jr z,_skip2 451 | _skip 452 | ld a,(de) ;check if byte is empty 453 | or a 454 | inc de 455 | jr z,_lp ;if it is, check next byte 456 | 457 | _skip2 ;else return 458 | pop de 459 | ret 460 | ;jp waitForKeyRelease ;not needed since kDot is ignored when returning 461 | ;************************************************************************************ 462 | 463 | chkMemEnd ;check if end of usr memory reached 464 | ;IN: nothing | OUT: jumps to errorHand if mem_end reached 465 | or a ;clear carry 466 | push hl 467 | ld hl,mem_end-4 468 | ;ld hl,savestates+2 ;DEBUG 469 | sbc hl,de ;subtract current mempos from mem_end-3 470 | pop hl 471 | ret nc 472 | 473 | saveError ;handling out of memory errors 474 | pop hl ;pop useless return address 475 | 476 | ld hl,savestateLUT ;delete savestateLUT entry 477 | ld a,(StateSelect) 478 | add a,a 479 | add a,a 480 | ld e,a 481 | ld d,0 482 | add hl,de 483 | xor a 484 | ld (hl),a 485 | inc hl 486 | ld (hl),a 487 | 488 | ld a,2 ;set error code 489 | jp errorHand0 490 | 491 | ;************************************************************************************ 492 | load ;load a song from a backup savestate. 493 | ;IN: # of savestate to load in (StateSelect) | OUT: nothing, AF,BC,DE,HL destroyed. 494 | call zap ;clear work area 495 | 496 | ld a,(version) ;check savestate format version 497 | ;or a 498 | dec a 499 | jr z,_ldstart 500 | ld a,6 ;if version != 0, abort loading and generate error 501 | jp errorHand0 502 | 503 | _ldstart 504 | ; ld hl,ptns ;initialize sequence with #ff bytes 505 | ; ld de,ptns+1 ;this is all unnecessary since we zap before 506 | ; ld bc,1025 507 | ; ld a,#ff 508 | ; ld (hl),a 509 | ; ldir 510 | ; 511 | ; xor a ;initialize rest of work area with #00 512 | ; ld (hl),a 513 | ; ld bc,16*256 514 | ; ldir 515 | 516 | ld hl,savestateLUT ;set pointer to savestate LUT 517 | ld a,(StateSelect) ;calculate offset 518 | add a,a 519 | add a,a ;NEW: each LUT entry is now 4 bytes 520 | ld e,a 521 | ld d,0 522 | add hl,de ;add it to LUT pointer 523 | ld e,(hl) ;get address of savestate to load in DE 524 | inc hl 525 | ld a,(hl) 526 | or a ;trap empty savestates 527 | ld a,5 528 | jp z,errorHand0 ;abort and ouput error if empty savestate encountered 529 | ld d,(hl) 530 | ex de,hl ;move it to HL 531 | ld de,musicData ;set destination address 532 | 533 | _ldvars ;load global song vars 534 | ldi ;speed 535 | ldi ;usr drum pointer 536 | ldi 537 | ldi ;loop point 538 | 539 | _ldseq ;load sequence 540 | ld a,(hl) ;check for seq. end marker (#ff) 541 | cp #ff 542 | jr z,_ldptns ;continue with loading patterns if end marker found 543 | ldi ;else, move byte from savestate to work area 544 | jr _ldseq 545 | 546 | _ldptns 547 | inc hl ;adjust pointer to savestate 548 | ld de,ptn00 ;adjust pointer to work area 549 | 550 | _ldptnlp 551 | ld a,(hl) ;get a byte from savestate 552 | cp #ff ;check for ptn area end marker (#ff) 553 | jr z,_ldfxptns ;if end marker is found, continue with loading fx patterns 554 | 555 | push hl ;preserve pointer to savestate 556 | ld h,0 ;init offset value 557 | 558 | cp #e0 ;check if byte >= #e0 ("empty patterns") 559 | jr c,_skip1 560 | sub #df ;offset = ([hl] - #df)*16 561 | ld l,a 562 | add hl,hl 563 | add hl,hl 564 | add hl,hl 565 | add hl,hl 566 | jr _skip3 567 | 568 | _skip1 569 | cp #d0 ;check if byte >= #d0 ("empty rows") 570 | jr c,_noCP ;if it isn't, we have normal uncompressed data 571 | sub #cf ;else, offset = [hl] - #cf 572 | ld l,a 573 | 574 | _skip3 575 | add hl,de ;add offset to work area pointer 576 | ex de,hl 577 | pop hl ;restore savestate pointer 578 | inc hl ;increment savestate pointer 579 | jr _ldptnlp ;read next byte 580 | 581 | _noCP 582 | pop hl ;restore savestate pointer 583 | ldi ;transfer byte to work area and increment pointers 584 | jr _ldptnlp ;read next byte 585 | 586 | 587 | _ldfxptns 588 | ldfxpnts 589 | inc hl ;adjust pointer to savestate 590 | ;ld de,fxptn00 ;adjust pointer to work area 591 | 592 | _ldfxptnlp ;TODO: optimize ptn address finding by using fxptntab lookup 593 | ld de,fxptn00 ;adjust pointer to work area 594 | ld a,(hl) ;load ptn # 595 | 596 | cp #ff ;if ptn# == #ff, there are no fx patterns to load 597 | ret z 598 | 599 | push af 600 | ;and #7f 601 | and #3f ;mask out bit 6,7 602 | 603 | inc hl 604 | push hl 605 | 606 | ld h,0 607 | 608 | add a,a 609 | add a,a 610 | 611 | ld l,a ;patnum is max #3f, so can add a,a twice before loading into hl 612 | 613 | ;add hl,hl ;offset = ptn# * 32 614 | ;add hl,hl 615 | add hl,hl 616 | add hl,hl 617 | add hl,hl 618 | 619 | add hl,de ;add offset to work area pointer 620 | ex de,hl 621 | 622 | pop hl 623 | 624 | ld bc,32 ;copy 32 bytes 625 | ldir 626 | 627 | pop af 628 | cp #3f ;check if bit 7 of ptn# was set or ptn# was >#3f 629 | jr c,_ldfxptnlp ;TEST DEBUG 630 | ret ;else we're done. 631 | ;************************************************************************************ -------------------------------------------------------------------------------- /player.asm: -------------------------------------------------------------------------------- 1 | ;******************************************************************************* 2 | ;MUSIC PLAYER 3 | ;******************************************************************************* 4 | 5 | ;setup function for rowPlay 6 | ;******************************************************************************* 7 | 8 | rowPlay ;rowPlay subroutine 9 | call waitForKeyRelease 10 | 11 | ld a,(PlayerFlag) ;check if player is running 12 | or a 13 | jp nz,_ignore ;and ignore rowPlay if that's the case 14 | 15 | cpl 16 | ld (PlayerFlag),a ;set PlayerFlag to prevent double call 17 | 18 | ;call waitForKeyRelease 19 | 20 | xor a 21 | ld h,a 22 | ld d,a 23 | ld a,(OldCsrPos) 24 | call findCurrLineNoSeq ;find current line in sequence 25 | 26 | ld de,3 ;reading in backwards, therefore add 3 to offset 27 | add hl,de 28 | ex de,hl 29 | 30 | 31 | ld bc,fxptn00 32 | 33 | ld a,(CsrPos) 34 | sub #50 35 | cp #f 36 | jr c,_skipadj 37 | sub 8 38 | _skipadj 39 | add a,a 40 | ld l,a 41 | ld h,0 42 | add hl,bc 43 | ld b,h 44 | ld c,l 45 | 46 | ld a,(de) 47 | add a,a ;a*2 48 | call calcPtnOffset+2 49 | push hl ;fx - ;stack+0 = ch1, stack+2 = ch2, stack+4 = ch3, stack+6 = fx 50 | 51 | ld bc,ptn00 52 | 53 | ld a,(CsrPos) 54 | sub #50 55 | cp #f 56 | jr c,_skipdiv 57 | sub 8 58 | _skipdiv 59 | ld l,a 60 | ld h,0 61 | add hl,bc 62 | ld b,h 63 | ld c,l 64 | 65 | call calcPtnOffset 66 | push hl ;ch3 67 | 68 | call calcPtnOffset 69 | push hl ;ch2 70 | 71 | call calcPtnOffset 72 | push hl ;ch1 73 | 74 | ld (oldSP),sp 75 | 76 | ld hl,_next 77 | ld (rowplaySwap),hl 78 | 79 | xor a 80 | out (kbd),a 81 | 82 | jp rdnotesRP ;call player 83 | _next 84 | pop hl ;clean stack and reset switch 85 | pop hl 86 | pop hl 87 | pop hl 88 | ld hl,rdnotes 89 | ld (rowplaySwap),hl 90 | xor a ;clear PlayerFlag 91 | ld (PlayerFlag),a 92 | _ignore 93 | ;jp waitForKeyRelease 94 | ret 95 | 96 | 97 | ;******************************************************************************* 98 | ;main entry point for music player 99 | ;******************************************************************************* 100 | 101 | mplay 102 | play 103 | call waitForKeyRelease ;keyhandler is very fast, so make sure there are currently no keys pressed 104 | 105 | init ;sandboxing the actual player so we can handle keypresses vs looping quickly 106 | ld de,ptns 107 | initrp ;init point for row play 108 | ld hl,-12 ;calculate stack restore point 109 | add hl,sp 110 | ld (oldSP),hl 111 | 112 | push de 113 | call resetFX0 114 | 115 | ld hl,(musicData+1) ;load user (drum) sample pointer \ this will become redundant, (usrdrum) can be set on loading song 116 | ld (usrdrum),hl ;save it to drum table / and if song is already in mem, it is then also already loaded 117 | 118 | ld a,(looprow) ;set loop point 119 | ;add a,a ;A*4 120 | ;add a,a 121 | ld l,a 122 | ld h,0 123 | add hl,hl ;loop point x4 because each seqrow is 4 bytes 124 | add hl,hl 125 | ld de,ptns 126 | 127 | ld a,(de) ;while we're at it, check if player is set to start from an empty row (first pattern # = #ff) 128 | 129 | add hl,de ;and calculate loop point 130 | ld (looppoint),hl 131 | pop de 132 | 133 | inc a ;continue "empty row" check 134 | ret z ;and exit if an "empty" row is found 135 | 136 | call rdnotes1 137 | 138 | init0 139 | call rdnotes0 140 | 141 | jp z,init0 ;loop if no key pressed 142 | 143 | ;************************************************************************************* 144 | rdnotes0 ;initialize read song data process 145 | looppoint equ $+1 146 | ld de,0 ;point song data pointer at loop point 147 | 148 | ld a,(de) ;check if loop point is still valid - exit with error if not 149 | inc a 150 | jp z,lpInvalidErr 151 | 152 | rdnotes1 153 | push de ;preserve song data pointer 154 | xor a 155 | out (kbd),a 156 | jr ptnselect 157 | 158 | ;************************************************************************************* 159 | ptnselect_playPtnLoop 160 | pop hl ;clean stack - PROBABLY BETTER TO USE LD SP,nnnn 161 | pop hl 162 | pop hl 163 | pop hl 164 | pop de 165 | dec de 166 | dec de 167 | dec de 168 | dec de 169 | jr ptnselect_mod 170 | ptnselect0 171 | pop hl ;clean stack - PROBABLY BETTER TO USE LD SP,nnnn 172 | pop hl 173 | pop hl 174 | pop hl 175 | ;************************************************************************************* 176 | ptnselect ;FIRST, set up ptn sequence pointers and push them (preserve song seq pointer in mem?) 177 | ;SECOND, check if row counter has reached 0 178 | ;THIRD, pop back ptn sequence pointers and read in data 179 | pop de ;10 ;restore song data pointer 180 | ptnselect_mod 181 | ld a,#11 ;7 ;initialize ptn position counter - all patterns are 16 rows long 182 | ld (reptpos),a ;13 183 | 184 | ld a,(de) ;7 ;load ptn# ch1 185 | cp #ff ;7 ;check for end marker 186 | ret z ;11/5 ;exit if found 187 | 188 | 189 | ld h,HIGH(ptntab) ;point to pattern position LUT 190 | add a,a ;4 ;A=A*2 191 | ld l,a ;4 192 | ld c,(hl) ;7 ;seq pointer ch1 to bc 193 | inc hl ;6 ;TODO: in theory inc l should be sufficient? 194 | ld b,(hl) ;7 195 | push bc ;11 196 | 197 | inc de ;6 ;point to ch3 198 | ld a,(de) ;7 ;load ptn# ch3 199 | add a,a ;4 200 | ld l,a ;4 201 | ld c,(hl) ;7 ;seq pointer ch3 to bc 202 | inc hl ;6 203 | ld b,(hl) ;7 204 | push bc ;11 205 | 206 | inc de ;6 ;point to ch2 207 | ld a,(de) ;7 ;load ptn# ch2 208 | add a,a ;4 209 | ld l,a ;4 210 | ld c,(hl) ;7 ;seq pointer ch2 to bc 211 | inc hl ;6 212 | ld b,(hl) ;7 213 | push bc ;6 214 | 215 | inc de ;6 ;point to fx 216 | ld a,(de) ;7 ;load ptn# fx 217 | ld hl,fxptntab ;10 218 | add a,a ;4 219 | add a,l ;4 220 | ld l,a ;4 221 | IF MODEL != TI8X || MODEL != TI8XS ;fx ptn table crosses page boundary on 82/83 TODO: conditional should depend on the table crossing the page bound 222 | jr nc,psskip4 ;12/7 223 | inc h ;4 224 | psskip4 225 | ENDIF 226 | ld c,(hl) ;7 ;seq pointer fx to bc 227 | inc hl ;6 228 | ld b,(hl) ;7 54t 229 | 230 | inc de ;6 ;point to next row 231 | 232 | exx ;4 233 | 234 | pop bc ;10 ;seq pointer ch2 to bc' 235 | pop de ;10 ;seq pointer ch3 to de' 236 | pop hl ;10 ;seq pointer ch1 to hl' 237 | 238 | exx ;4 239 | 240 | push de ;11 ;stack loc. 1 - sng seq pointer 241 | push bc ;11 ;stack loc. 2 - fx ptn pointer 242 | 243 | exx ;4 244 | 245 | push bc ;11 ;stack loc. 3 - ch2 ptn pointer 246 | push de ;11 ;stack loc. 4 - ch3 ptn pointer 247 | push hl ;11 ;stack loc. 5 - ch1 ptn pointer 248 | 249 | ;************************************************************************************* 250 | rdnotes ;read in next step from song data 251 | ;ch1 - sp, ch2 - de, ch3 - bc, speed - de' 252 | 253 | ld hl,reptpos ;10 ;update pattern row counter 254 | dec (hl) ;11 255 | ptnLoopSwitch equ $+1 256 | jr z,ptnselect0 ;12/7 257 | 258 | rdnotesRP ;entry point for RowPlay 259 | ld h,HIGH(NoteTab) ;7 ;point to frequency LUT 260 | pop bc ;10 ;ch1 ptn pointer to bc 261 | ld a,(bc) ;7 262 | inc bc ;6 ;increment ptn pos pointer 263 | add a,a ;4 264 | ld l,a ;4 ;set offset in freq.LUT 265 | 266 | ld a,(hl) ;7 ;lookup lo byte of frequency value 267 | ld (ch1),a ;13 ;and store it to base counter 268 | inc l ;4 269 | ld a,(hl) ;7 270 | ld (ch1+1),a ;13 ;and store it to base counter 271 | 272 | pop de ;10 ;ch2 ptn pointer to de 273 | ld a,(de) ;7 274 | inc de ;6 ;increment ptn pos pointer 275 | add a,a ;4 276 | ld l,a ;4 277 | 278 | ld a,(hl) ;7 ;get freq.counter for ch2(!) 279 | inc l ;4 280 | ld h,(hl) ;7 281 | ld l,a ;4 282 | ld (ch3),hl ;16 283 | 284 | exx ;4 285 | 286 | ld h,HIGH(NoteTab) ;7 ;reset freq.LUT pointer 287 | pop bc ;10 ;ch3 ptn pointer to bc' 288 | ld a,(bc) ;7 289 | inc bc ;6 290 | add a,a ;4 291 | ld l,a ;4 292 | 293 | ld a,(hl) ;7 ;get freq.counter for ch3(!) 294 | inc l ;4 295 | ld h,(hl) ;7 296 | ld l,a ;4 297 | ld (ch2),hl ;16 298 | 299 | or h ;4 ;deactivate pitch slide and table execution on rest notes, else activate 300 | ld i,a ;9 ;(de)activate table execution 301 | 302 | or a 303 | jr z,_disable9xx ;disable 9xx glitch effect on rests 304 | ld a,#57 305 | 306 | _disable9xx 307 | ld (ch3GlitchEnable),a 308 | 309 | pop de ;10 ;fx ptn pointer to de 310 | ld a,(de) ;7 ;read drum/fx cmd 311 | 312 | and %11110000 ;7 ;check for drum trigger (lower nibble) 313 | jp nz,drums ;10 314 | 315 | ld a,#ee ;7 ;deactivate drum (#ee = xor n) 316 | drx 317 | ld (noDrum),a ;13 318 | 319 | ld a,(de) ;7 ;read fx cmd again 320 | and %00001111 ;7 ; 321 | inc de ;6 ;point to fx parameter 322 | jp nz,fxselect ;10 323 | 324 | fxreturn 325 | inc de ;6 ;point to next row 326 | 327 | push de ;11 ;stack 2 328 | push bc ;11 ;stack 3 329 | 330 | ch3 equ $+1 ;misnomer, this is ch2 331 | ld bc,0 ;10 ;BC' is base divider value for ch2 332 | ld iy,0 ;14 ;reset ch2 accu 333 | 334 | xtab equ $+2 335 | ld ix,ptn00 ;14 ;pattern pointer for "execute note table" effect 336 | 337 | ch2 equ $+1 ;misnomer, this is ch3 338 | ld de,0 ;10 ;DE' holds the base counter for ch3 339 | ch3Phase equ $+2 340 | ld hl,0 ;10 ;reset ch3 accu 341 | 342 | exx ;4 343 | push de ;11 ;stack 4 344 | push bc ;11 ;stack 5 345 | 346 | drumtrig equ $+1 347 | ld bc,0 ;10 348 | 349 | cspeed equ $+2 350 | ld de,#1000 ;10 ;speed 351 | 352 | ch1 equ $+1 353 | ld sp,#0000 ;10 ;load base frequency counter val 354 | 355 | ld hl,0 ;10 ;HL holds "add" value for ch1, zero it 356 | 357 | maskD equ $+1 ;panning switch for drum ch 358 | ld a,lp_off ;initialize output mask for drum channel 359 | ex af,af' 360 | 361 | ;************************************************************************************* 362 | noXFX 363 | playnote ;synthesize and output current step 364 | 365 | ld a,(bc) ;7 ;load sample byte 366 | drumswap2 367 | nop ;4 ;daa/cpl/etc 368 | noDrum 369 | dru equ $+1 370 | add a,0 ;7 ;add current drum pitch counter - swapped out with xor n (#ee) when not playing a drum (add a,n = #c6) 371 | ld (dru),a ;13 ;and save it as current pitch counter 372 | 373 | muteD ;mute switch for drums 374 | jp nc,waitD ;10 ;jp nc = #d2, jp = #c3 375 | 376 | ex af,af' ;4 ;load output mask for drum channel 377 | out (link),a ;11 ;output drum channel state 378 | ;---- CH2: 96t 379 | 380 | drumswap ;switch for drum mode. inc bc = #03, dec bc = #0b, inc c = #0c, dec c = #0d, nop 381 | inc bc ;6 ;increment sample data pointer 382 | panD equ $+1 383 | xor lp_sw ;7 ;toggle output mask 384 | ret c ;5 ;43t, ret never taken 385 | 386 | ex af,af' ;4 387 | outdr 388 | ;ex af,af' ;4 389 | 390 | add hl,sp ;11 ;add current counter to base freq.counter val. ch1 and save result in HL 391 | phaseshift1 equ $+1 392 | ld a,#80 ;7 ;set duty 393 | cp h ;4 394 | mute1 ;mute switch for ch1 395 | sbc a,a ;4 396 | or lp_off ;7 397 | pan1 equ $+1 398 | and lp_on ;7 399 | 400 | exx ;4 ;back to the normal register set 401 | add hl,de ;11 ;update counter ch3 402 | out1 403 | out (link),a ;11 ;output state ch1 404 | ;----- DRUMS: 88/88t 405 | 406 | jr nc,noSlideShift ;12/7 407 | 408 | ch3grind equ $+1 409 | rlc a ;8 ;#cb 07, swap with rlc d (#cb 02) for "grind" effect 410 | 411 | ld a,e ;4 412 | slideDirectionA 413 | pitchslide equ $+1 414 | add a,0 ;7 ;add a,n = #ce, sub n = #d6 415 | ld e,a ;4 416 | 417 | slideDirectionB 418 | adc a,d ;4 ;sbc a,a ;adc a,d; sub e = #938a | sbc a,a; add a,d = #829f 419 | sub e ;4 ;add a,d 420 | ld d,a ;4 421 | ;34 ;+34 -25 = +9t but 18t saved because HL' is now single-use!!! 422 | 423 | noShiftRet 424 | phaseshift3 equ $+1 ;switch for phase shift/set duty cycle 425 | ld a,#80 ;7 426 | cp h ;8 427 | mute3 428 | sbc a,a ;4 ;result of this will be either #00 or #ff. for mute, swap #9f (sbc a,a) with #97 (sub a,a) 429 | or lp_off ;7 430 | pan3 equ $+1 431 | and lp_on ;7 ;and thus we derive the output state 432 | out3 433 | out (link),a ;11 434 | ;---- CH1: 82t 435 | 436 | add iy,bc ;15 ;add counters ch2 437 | 438 | syncSwitch ;ch2 Duty Modulation FX 439 | sbc a,a ;4 ;supply sync with main osc for duty modulation fx (sub a,a = #97; sbc a,a = #9f) 440 | 441 | ;and 0, xor/add = regular mode 442 | ;and n, xor = synced pwm mod --> 7xx: xx=0 off, xx < #7f fast pwm, xx > #7f synced pwm 443 | ;and n, add = SID/PWM --> 5xx w/ xx > #80 -> n = xxf (so 581 would be regular SID) 444 | ;add n, add = fastPWM/auto chord 445 | 446 | ;<=580: dutyModSwitch1 = [AND N, dutyModSwitch2 = XOR/ADD N,] dutyMod = 0, phaseShift = xx 447 | ;>580: dutyModSwitch1 = [AND N, dutyModSwitch2 = ADD N,] dutyMod = xxf 448 | 449 | ;=700: dutyModSwitch1 = AND N, dutyModSwitch2 = ADD N, dutyMod = 0, sync on [, phaseShift = #80] 450 | ;<780: dutyModSwitch1 = ADD N, dutyModSwitch2 = ADD N, dutyMod = xx, sync off 451 | ;>=780: dutyModSwitch1 = AND N, dutyModSwitch2 = XOR N, dutyMod = xx - #7f, sync on 452 | 453 | ;add n, xor = also valid, but for what? 454 | dutyModSwitch1 455 | dutyMod equ $+1 456 | and #0 ;7 ;and n = #e6; add a,n = #c6 457 | dutyModSwitch2 458 | phaseshift2 equ $+1 459 | add a,#80 ;7 ;add a,n = #c6; xor n = #ee 460 | ld (phaseshift2),a ;13 461 | ;keycheck here wouldn't work, would need to reload A 462 | cp iyh ;8 463 | mute2 464 | sbc a,a ;4 465 | or lp_off ;7 466 | pan2 equ $+1 467 | and lp_on ;7 468 | out2 469 | exx ;4 470 | 471 | out (link),a ;11 472 | ;---- CH3: 87t 473 | readkeys ;check if a key has been pressed 474 | in a,(kbd) ;11 475 | cpl ;4 ;COULD IN THEORY OPTIMIZE THIS AWAY 476 | or a ;4 477 | jr nz,keyPressed ;12/7 ;and exit if necessary 478 | 479 | reentry 480 | 481 | timerHold 482 | dec e ;4 ;update timer lo byte 483 | ;swap with inc a for synth mode (hold row) - a is always 0 at this point so inc a reliably returns nz 484 | ;dec e = #1d, inc a = #3c 485 | jp nz,playnote ;10 486 | ;353 487 | 488 | dec d ;update timer hi-byte 489 | xFX equ $+1 490 | jp nz,noXFX ;execute extended fx if present, and jump @playnote 491 | 492 | oldSP equ $+1 493 | ld sp,0 ;retrieve SP 494 | rowplaySwap equ $+1 ;switch for jumping to exitRowplay instead 495 | jp rdnotes 496 | 497 | ;************************************************************************************* 498 | noSlideShift 499 | 500 | ret c ;5 ;timing, ret never taken 501 | ch3GlitchAdd equ $+1 502 | ld a,#0 ;7 ;disable = 0 503 | add a,d ;4 504 | ch3GlitchEnable 505 | ld d,a ;4 ;#57, temporarily disable with nop 506 | jp noShiftRet ;10+12=34 507 | 508 | ;************************************************************************************* 509 | noteCut ;note cut effect for ch1 510 | nLength equ $+1 511 | ld a,0 ;update length counter 512 | dec a 513 | ld (nLength),a 514 | jr nz,noXFX ;resume playback if length counter != 0 515 | ld hl,0 ;else, zero freq. counters 516 | ld sp,hl 517 | nLengthBackup equ $+1 518 | ld a,0 ;reset length counter 519 | ld (nLength),a 520 | jp playnote ;resume playback 521 | 522 | ;************************************************************************************* 523 | execTable ;execute note table effect ch3 524 | ;TODO: preserve HL'? 525 | 526 | ld a,i ;skip table execution on rests 527 | jr z,playnote 528 | exx 529 | ld (_HLrestore),hl 530 | ld h,HIGH(NoteTab) ;point to frequency table 531 | ld a,(ix+0) ;read note byte 532 | inc ix ;inc pattern pointer 533 | add a,a ;fetch new freq.counter value 534 | ld l,a 535 | ld e,(hl) 536 | inc l 537 | ld d,(hl) 538 | _HLrestore equ $+1 539 | ld hl,0 540 | exx 541 | 542 | jp playnote ;resume playback 543 | 544 | ;************************************************************************************* 545 | keyPressed 546 | ld (counterSP),sp ;20 ;save reload value (to be used after keyhandling) 547 | ld sp,(oldSP) 548 | 549 | push de ;preserve all counters 550 | push bc ;TODO: push HL'/pop HL' 551 | push hl 552 | exx 553 | push de 554 | push hl 555 | push bc 556 | ex af,af' 557 | push af 558 | 559 | call keyhand 560 | 561 | pop af 562 | ex af,af' 563 | 564 | pop bc ;retrieve all counters 565 | pop hl 566 | pop de 567 | exx 568 | pop hl 569 | pop bc 570 | pop de 571 | 572 | counterSP equ $+1 573 | ld sp,0 574 | 575 | xor a 576 | out (kbd),a 577 | 578 | jp reentry ;and continue playing 579 | 580 | ;************************************************************************************* 581 | waitD 582 | ex af,af' ;4 ;load output mask for drum channel 583 | out (link),a ;11 ;output drum channel state 584 | ;---- CH2: 96t 585 | ex af,af' 586 | ; fxswap1 587 | ; fxswap2 equ $+1 588 | ; dw 0 ;8 ;swap with rlc h (cb 04) for noise/glitch effect, with rlc l (cb 05) for phase effect 589 | ; ;TODO: could be optimized, rlc a to deactivate 590 | noiseEnable equ $+1 591 | rlc a ;8 ;switch for enabling ch1 noise effect. rlc a (cb 07) = off, rlc h (cb 04) = on, rlc l (cb 05) = pitch inacc. (usused) 592 | jp outdr ;10 593 | ;15+18+10=43 594 | 595 | ;************************************************************************************* 596 | 597 | drums ;select drum 598 | ld hl,samples-2 ;point to beginning of sample pointer table - 2 (because minimum offset will be +2) 599 | rra ;divide drum # by 8 to get offset in table (carry is cleared before calling drum select) 600 | rra 601 | rra 602 | add a,l ;add offset to (h)l 603 | ld l,a 604 | ld a,(hl) ;fetch drum data pointer 605 | inc l 606 | ld h,(hl) 607 | ld l,a 608 | ld (drumtrig),hl 609 | ld a,#c6 ;#c6 = ld a,n 610 | jp drx 611 | 612 | ;************************************************************************************* 613 | fxselect ;select fx 614 | dec a ;calculate jump 615 | add a,a 616 | add a,a 617 | ld (_jump),a 618 | _jump equ $+1 619 | jr $ 620 | 621 | fxJumpTab 622 | jp fx1 623 | nop 624 | jp fx2 625 | nop 626 | jp fx3 627 | nop 628 | jp fx4 629 | nop 630 | jp fx5 631 | nop 632 | jp fx6 633 | nop 634 | jp fx7 ;fx7 635 | nop 636 | jp fx8 ;fx8 637 | nop 638 | jp fx9 ;fx9 639 | nop 640 | jp fxA 641 | nop 642 | jp fxB 643 | nop 644 | jp fxC 645 | nop 646 | jp fxD 647 | nop 648 | jp fxE 649 | nop 650 | 651 | fxF ;#0f = set speed 652 | ld a,(de) 653 | ld l,a 654 | and #3f 655 | ld (cspeed),a 656 | ld a,l 657 | and #c0 658 | ld (cspeed-1),a 659 | jp fxcont 660 | 661 | ptnBreak_pm_loop 662 | ld a,(reptpos) ;break ptn (pattern loop playmode) 663 | cp #10 664 | jp z,fxreturn ;ignore cmd if triggered on the first pattern row 665 | pop de 666 | dec de 667 | dec de 668 | dec de 669 | dec de 670 | jp ptnselect_mod 671 | ptnBreak 672 | ld a,(reptpos) ;break ptn 673 | cp #10 ;ignore cmd if triggered on the first pattern row 674 | jp nz,ptnselect ;select next ptn if found ATTN: leaves register set swapped! 675 | jp fxreturn 676 | 677 | fxB ;#0b = break/ptn loop cmd 678 | ld a,(de) ;if param=0 679 | or a 680 | fxb_pm_loop_switch equ $+1 681 | jr z,ptnBreak ;break ptn 682 | 683 | _ptnloop 684 | ptnreptpos equ $+1 685 | ld a,0 686 | sub 1 687 | jp z,fxcont0 ;if rept.counter is about to reach 0, all loops have been executed -> reset counter and proceed as normal 688 | jp nc,execPtnRept ;if rept.counter is now -1, initialize ptn loop 689 | 690 | setupPtnRept 691 | ld a,(de) ;x = # of repeats, y = # of lines to jump back 692 | and #f 693 | inc a 694 | ld h,a 695 | ld a,(reptpos) 696 | add a,h 697 | cp #12 698 | jp nc,fxcont ;invalidate effect if backjump crosses pattern boundary 699 | 700 | ld (xreptPos),a ;TODO: Need to prevent nested Bxy loops. Maybe. 701 | 702 | ld a,(de) 703 | and #f0 704 | rra 705 | rra 706 | rra 707 | rra 708 | 709 | execPtnRept 710 | ld (ptnreptpos),a 711 | xreptPos equ $+1 712 | ld a,0 713 | ld (reptpos),a 714 | ld a,(de) 715 | and #f 716 | inc a ;y=0 means jump back 1 row, because pointers are already incremented 717 | neg 718 | exx 719 | ld l,a ;load to HL and sign-extend 720 | ld h,#ff 721 | ex de,hl 722 | add hl,de ;set ch1 pointer 723 | ex de,hl 724 | add hl,bc ;set ch2 pointer 725 | ld b,h 726 | ld c,l 727 | exx 728 | ld l,a 729 | ld h,#ff 730 | ex de,hl 731 | add hl,de ;*2 because fx ptns take 2 bytes per row 732 | add hl,de 733 | ex de,hl 734 | add hl,bc ;set ch3 pointer 735 | ld b,h 736 | ld c,l 737 | jp fxcont 738 | 739 | 740 | fx1 ;#01 = set panning 741 | ld a,(de) 742 | 743 | pch1 744 | rrca 745 | jp c,setright1 746 | rrca 747 | jp c,setleft1 748 | ex af,af' 749 | ld a,lp_on 750 | ld (pan1),a 751 | ex af,af' 752 | 753 | pch2 754 | rrca 755 | jp c,setright2 756 | rrca 757 | jp c,setleft2 758 | ex af,af' 759 | ld a,lp_on 760 | ld (pan2),a 761 | ex af,af' 762 | 763 | pch3 764 | rrca 765 | jp c,setright3 766 | rrca 767 | jp c,setleft3 768 | ex af,af' 769 | ld a,lp_on 770 | ld (pan3),a 771 | ex af,af' 772 | 773 | pchD 774 | rrca 775 | jp c,setrightD 776 | rrca 777 | jp c,setleftD 778 | ;ex af,af' 779 | ld a,lp_sw 780 | ld (panD),a 781 | ld a,lp_off 782 | ld (maskD),a 783 | ;ex af,af' 784 | jp fxcont 785 | 786 | fx2 ;pitch slide up 787 | ld a,(de) 788 | ld (pitchslide),a 789 | ld a,#ce 790 | ld (slideDirectionA),a 791 | ld hl,#938a 792 | ld (slideDirectionB),hl 793 | jp fxcont 794 | 795 | fx3 ;pitch slide down 796 | ld a,(de) 797 | ld (pitchslide),a 798 | ld a,#d6 799 | ld (slideDirectionA),a 800 | ld hl,#829f 801 | ld (slideDirectionB),hl 802 | jp fxcont 803 | 804 | fx4 ;duty cycle ch1 805 | ld a,(de) 806 | ld (phaseshift1),a 807 | cp #81 ;if duty < #80, deactivate noise effect 808 | ld a,7 809 | ;jr c,Askip 810 | jr c,_disableNoise 811 | ld a,4 ;else, activate noise mode (formerly A01) 812 | 813 | _disableNoise 814 | ld (noiseEnable),a 815 | jp fxcont 816 | 817 | fxA 818 | ld a,(de) ;set ch3 phase. Can be modified as follows: if bit 7 is set, interpret bits 0..6 as bitmask toggeling various fx 819 | ld (ch3Phase),a 820 | jp fxcont 821 | 822 | 823 | fx5 ;duty cycle ch2 824 | ld a,(de) 825 | cp #81 ;if fx param > #80, switch to pwm sweep mode 826 | jr nc,_activatePWM 827 | 828 | ld (phaseshift2),a ;set duty 829 | xor a 830 | ld (dutyMod),a ;reset duty modulator 831 | ;ld a,#c6 ;deactivate pwm sweep 832 | ;ld (pwmswitch),a 833 | jp fxcont 834 | 835 | _activatePWM 836 | ;ld a,#ce 837 | ;ld (pwmswitch),a 838 | and #7f 839 | ld (dutyMod),a 840 | jp fxcont 841 | 842 | fx6 ;duty cycle ch3 843 | ld a,(de) 844 | cp #81 845 | jr nc,_activateGrind 846 | 847 | ld (phaseshift3),a 848 | ld a,7 849 | ld (ch3grind),a 850 | jp fxcont 851 | 852 | _activateGrind 853 | add a,a 854 | ld (phaseshift3),a 855 | ld a,2 856 | ld (ch3grind),a 857 | jp fxcont 858 | 859 | fx7 860 | ld a,(de) 861 | or a 862 | jr nz,_activate 863 | 864 | ld (dutyMod),a 865 | ld a,#e6 866 | ld (dutyModSwitch1),a 867 | ld a,#c6 868 | ld (dutyModSwitch2),a 869 | ld a,#9f 870 | ld (syncSwitch),a 871 | jp fxcont 872 | 873 | _activate 874 | cp #80 875 | jr c,_autochord 876 | 877 | sub #7f 878 | ld (dutyMod),a 879 | ld a,#e6 880 | ld (dutyModSwitch1),a 881 | ld a,#ee 882 | ld (dutyModSwitch2),a 883 | ld a,#9f 884 | ld (syncSwitch),a 885 | jp fxcont 886 | 887 | 888 | _autochord 889 | ld (dutyMod),a 890 | ld a,#c6 891 | ld (dutyModSwitch1),a 892 | ld (dutyModSwitch2),a 893 | ld a,#97 894 | ld (syncSwitch),a 895 | jp fxcont 896 | 897 | 898 | fx8 ;execute note table ch2 899 | ld a,(de) 900 | ;exx 901 | ld h,HIGH(ptntab) ;point to pattern position LUT 902 | add a,a ;A=A*2 903 | jr c,disableExt 904 | 905 | ld l,a 906 | ld a,(hl) ;lo-byte pattern pointer 907 | inc hl 908 | ld h,(hl) ;hi-byte pattern pointer 909 | ld l,a 910 | ld (xtab),hl 911 | ld hl,execTable 912 | ld (xFX),hl 913 | ;exx 914 | jp fxcont 915 | 916 | fx9 ;ch3 "glitch" effect 917 | ld a,(de) 918 | ld (ch3GlitchAdd),a 919 | jp fxcont 920 | 921 | fxC ;note cut ch1 922 | ld a,(de) 923 | or a 924 | jr z,disableExt 925 | ld (nLength),a 926 | ld (nLengthBackup),a 927 | ;exx 928 | ld hl,noteCut 929 | ld (xFX),hl 930 | ;exx 931 | jp fxcont 932 | 933 | disableExt ;disable extended effects (8xx, Cxx) 934 | ;exx 935 | ld hl,noXFX 936 | ld (xFX),hl 937 | ;exx 938 | jp fxcont 939 | 940 | fxD ;set drum mode. TODO: instead of awkward jump, point HL to table, get offset, store 941 | ld hl,drumModeTable1 942 | ld a,(de) 943 | and #0f ;calculate offset 944 | add a,l 945 | ld l,a 946 | ld a,(hl) 947 | ld (drumswap2),a 948 | 949 | ld hl,drumModeTable2 950 | ld a,(de) 951 | cp #50 952 | jr nc,_ignore 953 | 954 | and #70 955 | rra 956 | rra 957 | rra 958 | rra 959 | add a,l 960 | ld l,a 961 | ld a,(hl) 962 | ld (drumswap),a 963 | _ignore 964 | jp fxcont 965 | 966 | 967 | IF ((HIGH($))<(HIGH($+15))) 968 | org 256*(1+(HIGH($))) ;align to next page if necessary 969 | .WARNING drumModeTable1 crosses page 970 | ENDIF 971 | drumModeTable1 972 | db #00, #27, #8f, #1f, #2f, #79, #89, #88, #90, #91, #a0, #a1, #b0, #b1, #a8, #a9 973 | ; nop daa add a,a rra cpl ld c,a add a,c add a,b sub b sub c and b or b or b or c xor b xor c 974 | 975 | IF ((HIGH($))<(HIGH($+4))) 976 | org 256*(1+(HIGH($))) ;align to next page if necessary 977 | .WARNING drumModeTable2 crosses page 978 | ENDIF 979 | drumModeTable2 980 | db #03, #0b, #0c, #0d, #00 981 | ; inc bc dec bc inc c dec c nop 982 | 983 | 984 | fxE ;reset all fx 985 | ld a,(de) 986 | 987 | cp #80 ;if fx param >= 0x80, it's a reset fx 988 | jr c,_extfx 989 | 990 | and #7f 991 | call z,resetFX ;resetFX always returns with A=0 and Z-flag set 992 | dec a 993 | call z,resetFX1 994 | dec a 995 | call z,resetFX2 996 | call nz,resetFX3 997 | jp fxreturn 998 | _extfx 999 | and #3f ;make sure ptn # is valid 1000 | push de ;preserve original fx ptn pointer 1001 | 1002 | ld hl,fxptntab 1003 | add a,a 1004 | add a,l 1005 | ld l,a 1006 | IF MODEL != TI8X || MODEL != TI8XS ;fx ptn table crosses page boundary on 82/83 1007 | jr nc,_skip 1008 | inc h 1009 | _skip 1010 | ENDIF 1011 | ld e,(hl) ;seq pointer fx to de 1012 | inc hl 1013 | ld d,(hl) 1014 | 1015 | ld a,#c9 ;modify fxcont to contain a RET 1016 | ld (fxcont),a 1017 | 1018 | ld a,(de) ;read fx # 1019 | and #f ;mask out drum value 1020 | inc de ;inc fx pointer 1021 | call nz,fxextselect ;execute fx command 1022 | inc de 1023 | ld a,(de) 1024 | and #f 1025 | inc de 1026 | call nz,fxextselect 1027 | inc de 1028 | ld a,(de) 1029 | and #f 1030 | inc de 1031 | call nz,fxextselect 1032 | inc de 1033 | ld a,(de) 1034 | and #f 1035 | inc de 1036 | call nz,fxextselect 1037 | inc de 1038 | ld a,(de) 1039 | and #f 1040 | inc de 1041 | call nz,fxextselect 1042 | 1043 | ld a,#c3 ;restore jump at fxcont 1044 | ld (fxcont),a 1045 | pop de ;restore fx ptn pointer 1046 | jp fxreturn 1047 | 1048 | 1049 | fxextselect ;select fx 1050 | dec a ;calculate jump 1051 | add a,a 1052 | add a,a 1053 | ld (_jump),a 1054 | _jump equ $+1 1055 | jr $ 1056 | 1057 | fxExtJumpTab 1058 | jp fx1 1059 | nop 1060 | jp fx2 1061 | nop 1062 | jp fx3 1063 | nop 1064 | jp fx4 1065 | nop 1066 | jp fx5 1067 | nop 1068 | jp fx6 1069 | nop 1070 | jp fx7 ;fx7 1071 | nop 1072 | jp fx8 ;fx8 1073 | nop 1074 | jp fx9 ;fx9 1075 | nop 1076 | jp fxA 1077 | nop 1078 | ret ;fxB 1079 | ds 3 1080 | jp fxC 1081 | nop 1082 | jp fxD 1083 | nop 1084 | ret ;fxE 1085 | ds 3 1086 | jp fxF 1087 | 1088 | setright1 1089 | ex af,af' 1090 | ld a,lp_r 1091 | ld (pan1),a 1092 | ex af,af' 1093 | rrca 1094 | jp pch2 1095 | 1096 | setleft1 1097 | ex af,af' 1098 | ld a,lp_l 1099 | ld (pan1),a 1100 | ex af,af' 1101 | jp pch2 1102 | 1103 | setright2 1104 | ex af,af' 1105 | ld a,lp_r 1106 | ld (pan2),a 1107 | ex af,af' 1108 | rrca 1109 | jp pch3 1110 | 1111 | setleft2 1112 | ex af,af' 1113 | ld a,lp_l 1114 | ld (pan2),a 1115 | ex af,af' 1116 | jp pch3 1117 | 1118 | setright3 1119 | ex af,af' 1120 | ld a,lp_r 1121 | ld (pan3),a 1122 | ex af,af' 1123 | rrca 1124 | jp pchD 1125 | 1126 | setleft3 1127 | ex af,af' 1128 | ld a,lp_l 1129 | ld (pan3),a 1130 | ex af,af' 1131 | jp pchD 1132 | 1133 | setrightD 1134 | ;ex af,af' 1135 | ld a,lp_swl 1136 | ld (panD),a 1137 | ld a,lp_r 1138 | ld (maskD),a 1139 | ;ex af,af' 1140 | ;rrca 1141 | jp fxcont 1142 | 1143 | setleftD 1144 | ;ex af,af' 1145 | ld a,lp_swr 1146 | ld (panD),a 1147 | ld a,lp_l 1148 | ld (maskD),a 1149 | ;ex af,af' 1150 | jp fxcont 1151 | 1152 | fxcont0 1153 | ld (ptnreptpos),a 1154 | fxcont 1155 | jp fxreturn ;jp = #c3, ret = #c9 1156 | 1157 | ;************************************************************************************* 1158 | resetFX0 ;reset Bxy effect 1159 | xor a 1160 | ld (ptnreptpos),a 1161 | 1162 | resetFX ;reset all fx 1163 | 1164 | ld a,(musicData) ;reset speed 1165 | ld l,a 1166 | and #3f 1167 | ld (cspeed),a 1168 | ld a,l 1169 | and #c0 1170 | ld (cspeed-1),a 1171 | 1172 | resetFX1 1173 | ld a,#80 ;reset phase shift 1174 | ld (phaseshift1),a 1175 | ld (phaseshift2),a 1176 | ld (phaseshift3),a 1177 | 1178 | resetFX2 1179 | ld a,lp_sw ;reset panning switches 1180 | ld (panD),a 1181 | 1182 | ld a,lp_on 1183 | ld (pan1),a 1184 | ld (pan2),a 1185 | ld (pan3),a 1186 | 1187 | ld a,lp_off 1188 | ld (maskD),a 1189 | 1190 | resetFX3 1191 | ld a,#9f 1192 | ld (syncSwitch),a 1193 | 1194 | ld a,#e6 ;reset ch2 duty modulation setting 1 1195 | ld (dutyModSwitch1),a 1196 | 1197 | ld a,#c6 ;reset ch2 duty modulation setting 2 1198 | ld (dutyModSwitch2),a 1199 | 1200 | ld a,#03 ;reset drum counter mode 1201 | ld (drumswap),a 1202 | 1203 | ld a,#07 ;reset ch3 grind fx 1204 | ld (ch3grind),a 1205 | ld (noiseEnable),a 1206 | 1207 | xor a 1208 | ; ld (fxswap1),a ;reset A0x fx 1209 | ; ld (fxswap2),a 1210 | ld (pitchslide),a 1211 | ld (drumswap2),a ;reset drum value mode 1212 | ld (dutyMod),a ;reset ch2 duty modulator 1213 | ld (ch3Phase),a ;reset ch3 phase offset 1214 | ld (ch3GlitchAdd),a ;reset ch3 fx 9xx 1215 | 1216 | ld hl,noXFX ;reset extended FX 1217 | ld (xFX),hl 1218 | 1219 | ret ;must return with A=0 and Z-flag set 1220 | ;************************************************************************************* 1221 | lpInvalidErr ;handle error caused by invalid loop point created by deleting row to loop to in livemode 1222 | pop hl ;clean stack 1223 | ld a,4 1224 | jp errorHand 1225 | 1226 | ;************************************************************************************* 1227 | IF ((HIGH($+5))<(HIGH($+37))) 1228 | org 256*(1+(HIGH($))) ;align to next page if necessary 1229 | .WARNING sample table crosses page boundary 1230 | ENDIF 1231 | db 'XDRUM' 1232 | 1233 | ds 2 ;needed for sample LUT offset calculation 1234 | 1235 | samples ;sample table may not cross page boundary 1236 | dw kickdr ;1 kick 1237 | ;dw text_mem 1238 | IF MODEL = TI82 || MODEL = TI8P 1239 | dw 0 ;2 snare/hat 1240 | dw #569b ;3 metallic snare + low end 1241 | dw #3c0 ;4 short low noise/snare 1242 | dw #6aa3 ;5 "plick" 1243 | dw #5b24 ;6 periodic noise 1244 | dw #6ba4 ;7 short clap/click 1245 | dw #6940 ;8 periodic noise/snare 1246 | dw #67a0 ;9 ???! 1247 | dw #800 ;a double shot 1248 | dw #5e31 ;b tiny kick 1249 | ENDIF 1250 | IF MODEL = TI83 1251 | dw 8 ;2 snare/hat 1252 | dw #355 ;dw #569b ;3 metallic snare + low end 1253 | dw #4ca ;4 short low noise/snare 1254 | dw #491 ;dw #6aa3 ;5 "plick" 1255 | dw #19a2 ;dw #5b24 ;6 periodic noise 1256 | dw #20af ;dw #6ba4 ;7 short clap/click 1257 | dw #2361 ;dw #6940 ;8 periodic noise/snare 1258 | dw #25a6 ;dw #67a0 ;9 ???! 1259 | dw #2a40 ;dw #800 ;a double shot 1260 | dw #2bae ;dw #5e31 ;b tiny kick 1261 | ENDIF 1262 | IF MODEL = TI8X 1263 | dw #6e ;2 snare/hat 1264 | dw #12d1 ;dw #569b ;3 metallic snare + low end 1265 | dw #5fa ;dw #3c0 ;4 short low noise/snare 1266 | dw #13c0 ;dw #6aa3 ;5 "plick" 1267 | dw #154a ;dw #5b24 ;6 periodic noise 1268 | dw #16ad ;dw #6ba4 ;7 short clap/click 1269 | dw #2c60 ;TODO dw #19b2 ;dw #6940 ;8 periodic noise/snare 1270 | dw #17a9 ;dw #67a0 ;9 ???! 1271 | dw #1d3f ;dw #800 ;a double shot 1272 | dw #1f73 ;dw #5e31 ;b tiny kick 1273 | ENDIF 1274 | dw CsrTab ;c tiny laser 1275 | dw CsrTab2 ;d noise (better) 1276 | dw fxptn00+(32*32) ;e user defined sample 1277 | usrdrum 1278 | dw 0 ;f user defined pointer 1279 | 1280 | ;dw #300 ;3 heavy snare -- this one probably goes 1281 | ;dw initSCR 1282 | ;dw #54d2 ;d noise 1283 | ;dw #4e28 ;e noise 1284 | ;dw #5fcd 1285 | 1286 | ;IF ((HIGH(samples-2))<(HIGH(usrdrum+2))) 1287 | ;.ERROR sample table crosses page boundary 1288 | ;ENDIF 1289 | 1290 | kickdr 1291 | db #80, #80, #70, #70, #60, #60, #50, #50, #40, #40, #40, #30, #30, #30, #30 1292 | db #20, #20, #20, #20, #20, #10, #10, #10, #10, #10, #10, #8, #8, #8, #8, #8, #8, #8 1293 | db #4, #4, #4, #4, #4, #4, #4, #4, #2, #2, #2, #2, #2, #2, #2, #2, #2, #0 1294 | 1295 | 1296 | -------------------------------------------------------------------------------- /teststate.asm: -------------------------------------------------------------------------------- 1 | ;collapsed savestate - test song 2 | 3 | db #10 ;speed 4 | ;dw #5fcd ;usr drum 5 | 6 | IF MODEL = TI82 || MODEL = TI8P 7 | dw #5e31 8 | ENDIF 9 | 10 | IF MODEL = TI83 11 | dw #2bae 12 | ENDIF 13 | 14 | IF MODEL = TI8X || MODEL = TI8XS 15 | dw #1f73 16 | ENDIF 17 | db #01 ;loop point 18 | 19 | db #00,#02,#01,#00 ;ptn sequence 20 | db #00,#02,#01,#01 21 | db #ff 22 | 23 | ;ptn area 24 | db 24 ;regular note byte 25 | db #d6 ;#d6 -> d: 0-byte, 6: for the next 6+1 = 7 rows 26 | db 24,24,24,48 27 | db 43,43,43,43 28 | 29 | db #d1,24,#d5 30 | db 24,24,36 31 | db 41,41,41,41 32 | 33 | db 0,24,#d5 34 | db 24,0,24,24 35 | db 12,24,36,48 36 | 37 | db #ff ;end of ptn area 38 | 39 | 40 | ;fx ptn area 41 | db #01+#80 ;fx ptn# (#00). bit 7 set = last fx ptn. 42 | 43 | db #1f,#20 44 | db #20,0 45 | db #30,0 46 | db #20,0 47 | 48 | db #ff,#10 49 | db #f0,0 50 | db #f0,0 51 | db #f0,0 52 | 53 | db #90,0 54 | db #a0,0 55 | db 0,0 56 | db #c0,0 57 | 58 | db #d0,0 59 | db #e0,0 60 | db #f0,0 61 | db 0,0 62 | 63 | ;eof -------------------------------------------------------------------------------- /util.asm: -------------------------------------------------------------------------------- 1 | ;******************************************************************************* 2 | ;MISC UTILITIES 3 | ;******************************************************************************* 4 | 5 | calcPtnOffset ;calculate offsets in note data 6 | dec de 7 | ld a,(de) 8 | add a,a 9 | ld l,a 10 | ld h,0 11 | add hl,hl 12 | add hl,hl 13 | add hl,hl 14 | add hl,bc 15 | ret 16 | 17 | ;************************************************************************************ 18 | confirmAction ;wait for confirmation/abortion of user action 19 | ;IN: nothing | OUT: carry reset if confirmed, else abort 20 | 21 | setXYat #29, #b8 ;print CONF message 22 | printTwoChars CHAR_C, CHAR_O ;CO 23 | setXYat #2a, #b8 24 | printTwoChars CHAR_N, CHAR_F ;NF 25 | 26 | _rdkeys 27 | ld a,KBD_GROUP_ZERO ;read key 0 28 | out (kbd),a 29 | key_delay 30 | in a,(kbd) 31 | rra 32 | jp nc,_cancel ;if pressed, cancel user action 33 | 34 | ld a,KBD_GROUP_DOT ;read key . 35 | out (kbd),a 36 | key_delay 37 | in a,(kbd) 38 | rra 39 | jp nc,_confirm ;if pressed, confirm user action 40 | jr _rdkeys ;if no key pressed, try again 41 | 42 | _cancel 43 | scf ;set carry 44 | 45 | _confirm ;if user action confirmed, carry is already reset 46 | _exitc 47 | clrMsgArea ;clear message area 48 | push af ;preserve flags 49 | setXYat #29, #b2 ;delete CONF message and rest of msg area 50 | call clearPrintBuf 51 | call printBuf 52 | call printBuf 53 | setXYat #2a, #b8 54 | call printBuf 55 | setXYat #2b, #b2 56 | call printBuf 57 | 58 | pop af 59 | ret 60 | 61 | ;************************************************************************************ 62 | calculateCopyParams ;calculate block start, length and target line # 63 | ;IN: nothing | OUT: block start in DE, block length in BC and HL, current line # in A 64 | exx 65 | ld a,d ;D' holds old block start 66 | exx 67 | 68 | ;ld a,(CPS) ;calculate block start in memory 69 | ld l,a 70 | ld h,0 71 | add hl,hl 72 | add hl,hl 73 | ex de,hl ;block start - base offset now in DE 74 | 75 | ;ld a,(CPE) ;calculate block length in memory 76 | exx 77 | ld a,e ;E' holds old block end 78 | exx 79 | 80 | ld l,a 81 | ld h,0 82 | add hl,hl 83 | add hl,hl 84 | ;xor a ;TODO: optimzed 15-08-19 - carry should never be set at this point, so we don't need to reset it 85 | sbc hl,de 86 | inc hl 87 | inc hl 88 | inc hl 89 | inc hl ;block length now in HL 90 | 91 | call getCurrLineNo ;current line # now in A 92 | 93 | ld b,h ;block length now in BC 94 | ld c,l 95 | ret 96 | 97 | 98 | ;************************************************************************************ 99 | getCurrLineNo ;calculate the current line number 100 | ;IN: nothing | OUT: current line number in A | DESTROYED: C 101 | ld a,(CsrPos) 102 | and %11111000 103 | rra 104 | rra 105 | rra 106 | ld c,a 107 | ld a,(FirstLineMS) 108 | add a,c 109 | ret 110 | 111 | 112 | ;************************************************************************************ 113 | findCurrLine ;find the current line in the sequence 114 | ;IN: nothing | OUT: pointer to start of line in HL 115 | xor a 116 | ld h,a 117 | ld d,a 118 | 119 | ld a,(CsrPos) 120 | ld (OldCsrPos),a 121 | 122 | findCurrLineNoSeq ;entry point for finding the current row when not on seq.scr 123 | and %11111000 ;clear lower 3 bits of cursor pos value to get to the start of the line and clear carry 124 | rra ;divide by two 125 | ld e,a ;store in DE 126 | ld a,(FirstLineMS) ;read current first line 127 | ld l,a ;store in HL 128 | 129 | add hl,hl ;HL*4 to get offset of first line 130 | add hl,hl 131 | add hl,de ;add DE to get offset of current line 132 | ld de,ptns ;add base pointer 133 | add hl,de ;sequence pointer now in HL 134 | ret 135 | 136 | ;************************************************************************************ 137 | findNextUnused ;find next unused ptn in sequence 138 | ;IN: first # to check in A | OUT: next unused in A, Z if no unsed patterns found 139 | ld hl,ptns 140 | ld bc,256*4 141 | _chklp 142 | cpi ;iterate through the pattern sequence 143 | jr z,_used ;exit loop if match found (pattern used) 144 | cpi 145 | jr z,_used 146 | cpi 147 | jr z,_used 148 | cpi ;every 4th pattern is an fx pattern, so it's ignored 149 | ret po ;return if pattern was unused 150 | jr _chklp 151 | 152 | _used 153 | inc a ;if pattern was used 154 | cp #80 ;check if all patterns have been checked 155 | ret z ;and return if that's the case 156 | jr findNextUnused ;else, check next pattern 157 | 158 | 159 | isPtnFree ;check if a pattern is free 160 | ;IN: ptn # in A | OUT: Z if free, NZ if not free 161 | 162 | add a,a ;calculate offset 163 | ; ld l,a ;pattern # *2 to HL 164 | ; ld h,0 165 | ; add hl,hl 166 | ; add hl,hl 167 | ; add hl,hl 168 | ; ld de,ptn00 ;add base pointer 169 | ; add hl,de 170 | 171 | ld h,HIGH(ptntab) ;look up pattern address 172 | ld l,a 173 | ld a,(hl) 174 | inc hl 175 | ld h,(hl) 176 | ld l,a 177 | 178 | ld b,#10 179 | xor a 180 | 181 | chklp 182 | cp (hl) ;check value 183 | jr nz,_notfree ;exit loop if != 0 184 | inc hl ;else, increment pointer and check next val 185 | djnz chklp 186 | _notfree 187 | ret ;return with Z set if all values have been checked 188 | 189 | 190 | findNextUnusedFX ;find the next free fx pattern 191 | ;IN: first # to check in A | OUT: next unused in A, Z if no unsed patterns found 192 | ld hl,ptns 193 | ld bc,256*4 194 | _chklp 195 | cpi 196 | cpi 197 | cpi 198 | cpi 199 | jr z,_used 200 | ret po 201 | jr _chklp 202 | 203 | _used 204 | inc a ;if pattern was used 205 | cp #40 ;check if all patterns have been checked 206 | ret z ;and return if that's the case 207 | jr findNextUnusedFX ;else, check next pattern 208 | 209 | isFxPtnFree ;check if a pattern is free 210 | ;IN: ptn # in A | OUT: Z if free, NZ if not free 211 | 212 | ld de,fxptntab ;10 213 | add a,a ;4 214 | ld h,0 ;7 215 | ld l,a ;4 216 | add hl,de ;11 217 | ld a,(hl) ;7 218 | inc hl ;6 219 | ld h,(hl) ;7 220 | ld l,a ;4 221 | ;60t 222 | 223 | ld b,#20 224 | jr chklp-1 225 | 226 | 227 | 228 | 229 | ;******************************************************************************* 230 | divNoteVal ;split note value into octave and val w/in the octave 231 | ;IN: note val in A | OUT: octave in B, note val in C 232 | 233 | ld b,#ff 234 | dec a ;0=silence, so lowest actual note val is 1 -> decrement by 1 235 | _divlp ;effectively dividing A by 12 236 | inc b ;increment octave 237 | ld c,a ;preserve remainder 238 | sub 12 ;subtract 12 239 | jr nc,_divlp ;loop until result was <0 240 | 241 | ret 242 | 243 | ;************************************************************************************ 244 | 245 | ;************************************************************************************ 246 | findCurrPtn ;locate the currently selected pattern in memory 247 | ;IN: nothing | OUT: pattern pointer in DE 248 | 249 | ld a,(CPtn) ;read current ptn# TODO: optimize by moving this to after the findCurrFxPtn label 250 | 251 | findPtn ;find ptn in memory 252 | ld hl,ptntab ;10 ;point to pattern position LUT 253 | 254 | findCurrFxPtn ;entry point for finding fx pattern. A and HL need to be preset 255 | 256 | add a,a ;4 ;A=A*2 257 | add a,l ;4 258 | ld l,a ;4 259 | jr nc,_skip1 ;12/7 260 | inc h ;4 261 | _skip1 ;ptn pointer now at (HL) 262 | 263 | ld e,(hl) 264 | inc hl 265 | ld d,(hl) ;ptn pointer now in DE 266 | ret 267 | 268 | ;************************************************************************************ 269 | getSeqOffset ;get offset in ptn sequence based on current cursor pos on seq.screen 270 | ;IN: nothing | OUT: sequence pointer in HL, [current] ptn# in A,(CPtn) | destroyed: DE 271 | 272 | xor a ;clear carry 273 | ld h,a ;ld h,0 274 | ld d,a 275 | ld a,(CsrPos) ;read old cursor position (from seq.scr) 276 | rra ;divide by 2 277 | ld e,a 278 | ld a,(FirstLineMS) ;check first line on seq scr 279 | ld l,a 280 | add hl,hl ;offset*4 281 | add hl,hl 282 | add hl,de ;+ position offset = total offset in ptn sequence 283 | ld de,ptns ;add ptn sequence base 284 | add hl,de ;seq.pointer now in HL 285 | 286 | ld a,(hl) ;load ptn# into A 287 | ld (CPtn),a ;store it in (CPtn) 288 | ret 289 | 290 | ;************************************************************************************ 291 | 292 | 293 | 294 | ;************************************************************************************ 295 | hex2char ;convert hex value to character string (using custom font) 296 | ;input: A=hex byte | output: string in (charstring), A destroyed 297 | 298 | cp #ff ;check if we have an #ff byte 299 | jr z,hex2charFF 300 | 301 | hex2charNoFF 302 | push af ;preserve input byte 303 | and %00001111 ;extract lower nibble 304 | ld (CharString),a ;save it 305 | pop af ;retrieve input byte 306 | rra ;shift right x4 and clear bit 4-7 to extract upper nibble 307 | rra 308 | rra 309 | rra 310 | and %00001111 311 | ld (CharString+1),a 312 | ret 313 | 314 | hex2charFF 315 | ld a,#16 ;replace #ff with -- 316 | ld (CharString),a 317 | ld (CharString+1),a 318 | ret 319 | 320 | 321 | hex2charU ;convert upper nibble of hex value to right-aligned char and return it in A 322 | cp #ff 323 | jr z,hex2FF 324 | rra ;shift right x4 and clear bit 4-7 to extract upper nibble 325 | rra 326 | rra 327 | rra 328 | and %00001111 329 | ret 330 | 331 | hex2charL ;convert lower nibble of hex value to left-aligned char and return it in A 332 | cp #ff 333 | jr z,hex2FF 334 | and %00001111 335 | ret 336 | 337 | hex2FF ;replace hex digit with - (dash) 338 | ld a,#16 339 | ret 340 | --------------------------------------------------------------------------------