- Java 91.1%
- AGS Script 6.9%
- Python 2%
| .github/workflows | ||
| definitions | ||
| gradle/wrapper | ||
| scripts | ||
| src | ||
| .gitignore | ||
| build.gradle.kts | ||
| CLAUDE.md | ||
| gradle.properties | ||
| gradlew | ||
| gradlew.bat | ||
| LICENSE | ||
| MacOS-README.txt | ||
| missing_offsets.txt | ||
| README.md | ||
| settings.gradle.kts | ||
| TOKENIZER.md | ||
Portamos
A portable, JVM-based toolkit for working with AMOS Professional files on modern systems. The name is a play on portable AMOS.
AMOS Professional is a BASIC-like programming language for the Commodore Amiga, developed by François Lionet. Programs
are stored as tokenised binary files (.AMOS), and multimedia data is stored in memory bank files (.Abk).
Download
Downloads for Linux, Mac and Windows as well as fat jar in Releases
Features
| Feature | Status |
|---|---|
ASCII source (.Asc) → binary (.AMOS) |
✅ Working |
Binary (.AMOS) → ASCII source (.Asc) |
✅ Working |
| Compiled procedures (AMOSPro Compiler output) | ✅ Preserved |
Banks embedded in .AMOS files |
✅ Working |
| Resource bank read/write/export/import | ✅ Working |
| Sprite / Icon bank read/write/export/import | ✅ Working |
| Pac.Pic bank read/write/export/import | ✅ Working |
| Work / Data bank read/write/export/import | ✅ Working |
| AMAL bank read/write/export/import | ✅ Working |
| Menu bank read/write/export/import | ✅ Working |
| Sample bank read/write/export/import (WAV / 8SVX) | ✅ Working |
| Music bank read/write/export/import (WAV / 8SVX) | ✅ Working |
| Tracker bank read/write/export/import | ✅ Working |
Build requirements
- Java 21 (tested with Eclipse Temurin 21)
The Gradle wrapper (./gradlew) downloads Gradle automatically; no separate installation is needed.
Building
./gradlew build
This produces a fat JAR at build/libs/portamos-<version>-all.jar.
You can also run directly via Gradle:
./gradlew run --args="<subcommand> [options]"
CLI Reference
Run portamos help or portamos <subcommand> --help for full option listings.
list — detokenize a binary to ASCII source
portamos list input.AMOS output.Asc
portamos list input.AMOS output.Asc --definition definitions/turboplus.json
portamos list input.AMOS output.Asc --no-definition music --definition definitions/amcaf.json
Reads a binary .AMOS file and writes the corresponding AMOS Professional ASCII source file.
Compiled procedures (produced by the AMOSPro Compiler) are preserved as PEM-style base64 blocks in
the output so that the source can be round-tripped back through build without losing the compiled
body.
--definition <path.json> — Load an additional extension definition file before detokenizing
(repeatable).
--no-definition <id> — Skip a built-in extension definition by its ID (repeatable). Use this
when the program replaces a built-in extension with a third-party one — for example, AMCAF replaces
the Music extension at runtime, so you would pass --no-definition music --definition definitions/amcaf.json.
Known built-in IDs: Core, Music, Compact, Request, IOPorts, Compiler.
build — tokenize an ASCII source file
portamos build source.Asc output.AMOS
portamos build source.Asc output.AMOS --add-bank sprites.Abk --add-bank music.Abk
portamos build source.Asc output.AMOS --import-bank sprites/bank.json
portamos build source.Asc output.AMOS --definition definitions/turboplus.json
portamos build source.Asc output.AMOS --no-definition music --definition definitions/amcaf.json
portamos build source.Asc output.AMOS --fold
Reads an AMOS Professional ASCII source file and writes the corresponding binary .AMOS file.
Optionally attaches bank files directly (--add-bank) or assembles them from JSON (--import-bank).
--definition <path.json> — Load an additional extension definition file before tokenizing
(repeatable). Use this for third-party extensions not included in the built-in set. The release
archives include a definitions/ directory with definitions for known third-party extensions.
--no-definition <id> — Skip a built-in extension definition by its ID (repeatable). Use this
when the program replaces a built-in extension with a third-party one — for example, AMCAF replaces
the Music extension at runtime, so you would pass --no-definition music --definition definitions/amcaf.json.
Known built-in IDs: Core, Music, Compact, Request, IOPorts, Compiler.
--fold — Mark all Procedure blocks as folded in the AMOS editor by default (bit 7 of the
procedure flags byte). Without this flag, procedures are saved in the unfolded state.
disasm — export a bank to files
portamos disasm input.Abk output-dir/
portamos disasm --ilbm input.Abk output-dir/ # sprite sheet as IFF ILBM instead of PNG
portamos disasm --svx8 input.Abk output-dir/ # samples as IFF 8SVX instead of WAV
Exports the contents of any supported bank type to a directory. The output always includes a
bank.json metadata file plus type-specific data files:
| Bank type | Data files |
|---|---|
| Resource | spritesheet.png (or .iff), program_NNN.amui |
| Sprite/Icon | spritesheet.png (or .iff) |
| Pac.Pic | <name>.png (or .iff) |
| Music | instrument_NNN.wav (or .8svx) |
| Sample | sample_NNN.wav (or .8svx) |
| Tracker | <name>.mod |
| AMAL | script_NNN.amal |
| Work/Data | <name>.bin |
asm — assemble a bank from files
portamos asm bank.json output.Abk
Reads the bank.json produced by disasm and reassembles the binary .Abk file. The "type"
field in the JSON determines which importer is used.
raw — wrap a raw file into a bank
portamos raw payload.bin output.Abk --type WORK
portamos raw payload.bin output.Abk --type MUSIC --chip --bank-number 3
Wraps raw bytes in an AmBk envelope with the specified type. Valid types: WORK, DATA, MUSIC,
SAMPLES, ASM, CODE, AMAL, MENU, TRACKER, DATAS.
Developer commands
These are hidden in --help but documented in portamos dev-help:
portamos dump file.AMOS # token-level dump
portamos diff expected.AMOS actual.AMOS # token-level diff
portamos gen-ext-json input.Lib --slot N output.json # generate JSON from .Lib
Always use dump / diff instead of xxd or binary diff tools — they correctly handle
variable-length token payloads and show decoded annotations.
Bank JSON Format
All bank JSON files have a "type" field that identifies the bank and drives asm import.
Music bank
{
"type": "Music",
"bankNumber": 3,
"chipRam": true,
"instruments": [
{
"name": "Bass",
"volume": 45,
"loopStart": 112,
"loopLength": 3247,
"sample": "instrument_000.wav"
}
],
"songs": [
{
"name": "My Song",
"tempo": 15,
"sequence": [
[
0,
1,
2,
3,
65534
],
[
0,
1,
2,
3,
65534
],
[
0,
1,
2,
3,
65534
],
[
0,
1,
2,
3,
65534
]
]
}
],
"patterns": [
{
"voices": [
[
{
"command": "SET_INSTR",
"parameter": 0
},
{
"period": 254,
"duration": 16134
},
{
"period": 190,
"duration": 16134
}
],
...
]
}
]
}
songs[].sequence — four per-channel playlists; each is a list of 0-based pattern indices
terminated by 65534 (loop) or 65535 (stop). The four channels run independently — unlike
tracker/MOD format there is no shared row grid.
patterns[].voices — four independent note streams. Each item is either a note
(period + duration) or a command (command name + optional parameter). The duration is
the raw OldNote control word (bit 14 cleared); bits 13–8 encode per-note channel volume (0–63),
bits 7–0 encode the tick count. period is the Amiga hardware period (inversely proportional to
frequency; 0 = silence).
Known command names: SET_VOLUME, STOP_EFFECT, REPEAT, FILTER_ON, FILTER_OFF,
SET_TEMPO, SET_INSTR, ARPEGGIO, TONE_PORTAMENTO, VIBRATO, VOLUME_SLIDE,
PORTAMENTO_UP, PORTAMENTO_DOWN, DELAY, POSITION_JUMP.
Instrument samples are exported at 8363 Hz (Amiga standard tuning); actual playback pitch is determined by the note periods at runtime.
Sample bank
{
"type": "Samples",
"bankNumber": 1,
"chipRam": true,
"samples": [
{
"index": 0,
"name": "BanjoSyn",
"frequencyHz": 8363,
"file": "sample_000.wav"
},
{
"index": 1,
"name": "Empty",
"frequencyHz": 8363,
"empty": true
}
]
}
File Formats
.AMOS — Program binary
[16] version header (e.g. "AMOS Pro101v\0\0\0\0")
[4] code length in bytes (big-endian uint32)
[n] tokenised code — sequence of lines, each:
[1] line length in 16-bit words
[1] indent level (1-based)
[?] token stream
[2] 0x0000 end-of-line marker
[6+] "AmBs" + uint16 bank count + optional bank data
.Abk — Memory bank
[4] magic: "AmBk" / "AmSp" / "AmIc"
[2] bank number
[2] flags (bit 0: 0 = chip RAM, 1 = fast RAM)
[4] name+payload size (bit 31 set for chip-RAM AmBk banks)
[8] bank name (space-padded): "Music ", "Samples ", "Resource", …
[n] payload (format depends on bank type)
Project Structure
src/main/java/dev/rambris/amigaamos/
Main.java CLI entry point (subcommands: list/build/disasm/asm/raw/…)
tokenizer/
Tokenizer.java Public API: parse() + encode() + print()
AsciiParser.java ASCII source line → token list
AsciiPrinter.java Token list → ASCII source line (detokenizer)
BinaryEncoder.java Token list → binary bytes
BinaryDecoder.java Binary bytes → token list
AmosFileWriter.java Lines + banks → .AMOS file
AmosFileReader.java .AMOS file → AmosFile
TokenTable.java JSON definitions → token lookup
AmosDump.java Token dump and diff tool
ExtJsonGenerator.java .Lib binary → JSON skeleton
model/
AmosFile.java, AmosLine.java, AmosToken.java, AmosVersion.java
bank/
AmosBank.java Interface + type dispatch
BankWriter.java Interface: write(bank, path) / toBytes(bank)
AmBkCodec.java Shared AmBk header encode/decode
ResourceBank{Reader,Writer,Exporter,Importer}.java
SpriteBank{Reader,Writer,Exporter,Importer}.java
PacPicBank{Reader,Writer,Exporter,Importer}.java
MusicBank{Reader,Writer,Exporter,Importer}.java + MusicBank.java (model + Command enum)
SampleBank{Reader,Writer,Exporter,Importer}.java
TrackerBank{Reader,Writer,Exporter,Importer}.java
AmalBank{Reader,Writer,Exporter,Importer}.java
MenuBank{Reader,Writer,Exporter,Importer}.java
RawBank{Reader,Writer,Exporter,Importer}.java
src/main/resources/amos/definitions/
core.json, music.json, compact.json, request.json, ioports.json
definitions/ Third-party extension definitions (shipped in release archives)
turboplus.json TURBO Plus extension (slot 12, Manuel Andre)
reference/
AMOSProfessional/ Original AMOS Pro disk image and .Lib files
AmosProManual/ AMOS Pro manual
amiga-amos/ Source JSON token definitions (IntelliJ plugin)
amostools/extensions/ Third-party .Lib files
amos-file-formats.wiki Exotica file format docs
amos-music-bank-format.wiki Exotica Music bank format docs
Reference Material
| Path | Description |
|---|---|
reference/AMOSProfessional/ |
Full AMOS Pro disk image — original .Lib files, examples, accessories |
reference/AmosProManual/ |
AMOS Pro manual |
reference/amiga-amos/ |
JSON token definitions from intellij-amos |
reference/amostools/extensions/ |
Third-party .Lib extension files |
reference/amos-file-formats.wiki |
File format docs from Exotica |
reference/amos-music-bank-format.wiki |
Music bank format docs from Exotica |
Scripts
# Re-enrich JSON definitions from binary .bin tables
python3 scripts/enrich_definitions.py
# Re-generate per-signature offset schema after enrichment
python3 scripts/migrate_offsets.py
Known Limitations
- Symbol-table slot offsets (
unk2in named tokens) are written as zero; AMOS recomputes them at load time so programs run correctly, but the binary is not byte-identical to AMOS-produced files - ~66 core keyword definitions lack binary offsets (aliases and optional-suffix variants) and are silently skipped during tokenisation
- Compiled procedure bodies (AMOSPro Compiler output) are preserved opaquely as base64 in the ASCII source — the machine code is not disassembled or modifiable at the source level
- Third-party extensions beyond the five bundled JSON files require running
gen-ext-jsonto generate definition skeletons