CopperMod is a terminal music player for classic tracker and chip music formats. It started as a portable MED renderer, but is growing into a small playback stack with reusable C# backends and a Terminal.Gui based player application.
The project focuses on accurate replay behavior rather than format conversion. Backends render audio in small time slices, making them useful both for the CopperMod player and for other applications that need tracker playback.
- MED / OctaMED: MMD0-MMD3 parsing and Amiga-style playback work is underway.
- ProTracker MOD: 4-channel ProTracker playback with Amiga-style sample output.
- SID / RSID: native C# C64/SID emulation with cycle-counted register scheduling.
- CopperMod: terminal UI player with NAudio output and optional output shaping.
This is still an accuracy project in progress. Some advanced replay details, especially for SID analog behavior and difficult RSID tunes, are expected to keep improving over time.
Requires the .NET 10 SDK.
dotnet build .\CopperMod.sln
dotnet test .\CopperMod.slnCopperScreen's A500 runtime hot paths must not allocate managed objects after
warmup. Methods and types marked with [HotPath] are checked by the local
CopperMod.PerformanceAnalyzers Roslyn analyzer, and analyzer diagnostics are
treated as build errors.
Avoid LINQ, string formatting, closures, iterator or async state machines,
boxing, heap arrays, and reference-type new in hot-path code. Prefer
preallocated buffers, spans, fixed-size tables, ring buffers, value types, and
explicit counters. Cold paths such as disk loading, ROM loading, diagnostics,
crash logging, CopperBench browsing, and test/debug snapshots may allocate, but
must use [HotPathAllocationAllowed("reason")] with a non-empty reason when
they sit near hot-path code. Hot paths must not call allocation-allowed helpers.
Reusable libraries are published on NuGet:
| Package | Description |
|---|---|
| CopperMod.Abstractions | Shared module loading and rendering interfaces. |
| CopperMod.Med | MED / OctaMED MMD module parser and renderer. |
| CopperMod.ProTracker | ProTracker MOD parser and renderer. |
| CopperMod.Sid | PSID / RSID parser and SID renderer. |
| Copper68k | Reusable Motorola 68000-family CPU emulation core. |
| Copper6510 | Reusable MOS 6510 CPU emulation core. |
| CopperMod.Cust | Amiga CUST loader and Paula playback sandbox. |
| CopperDisk | Managed Amiga ADF and IPF disk image library. |
Install the playback backends separately:
dotnet add package CopperMod.Med
dotnet add package CopperMod.ProTracker
dotnet add package CopperMod.SidAll backend packages depend on CopperMod.Abstractions, which contains the
shared module loading and rendering interfaces.
CopperDisk is the managed Amiga disk-image package used by CopperScreen for
ADF and IPF loading:
dotnet add package CopperDiskCopperDisk package automation lives under scripts\nuget:
.\scripts\nuget\pack-copperdisk.ps1
.\scripts\nuget\publish-copperdisk.ps1 -PackagePath .\artifacts\packages\CopperDisk.1.0.0.nupkg -WhatIfCopperPad is staged for future NuGet publishing with the same script layout:
.\scripts\nuget\pack-copperpad.ps1
.\scripts\nuget\publish-copperpad.ps1 -PackagePath .\artifacts\packages\CopperPad.1.0.0.nupkg -WhatIfdotnet run --project .\CopperMod -- "path\to\tune.sid"If no file is provided, CopperMod tries to open the default MED test tune when it is available in the workspace.
CopperScreen is the Amiga 500 PAL emulator front-end in this workspace. It can
boot ADF, ADZ, DMS, and IPF disk images directly, or a ZIP containing exactly one
supported disk image:
dotnet run --project .\CopperScreen -- "path\to\disk.adf"
dotnet run --project .\CopperScreen -- "path\to\disk.adz"
dotnet run --project .\CopperScreen -- "path\to\disk.dms"
dotnet run --project .\CopperScreen -- "path\to\disk.ipf"
dotnet run --project .\CopperScreen -- "path\to\disk.zip"Disk image loading is provided by the managed CopperDisk library. It parses
standard and modern extended ADF images, decompresses ADZ and unencrypted
standard DD DMS images, and decodes SPS / CAPS IPF images into raw Amiga track
streams for CopperScreen's floppy path. This is still part of emulator bring-up,
so tricky protection schemes may continue to expose missing floppy-controller or
disk-DMA behavior.
By default CopperScreen starts from the expanded-copperstart profile config in
CopperScreen\Profiles. Profiles are JSON files that describe the machine
memory layout and Kickstart source. Select a bundled profile by id, or pass a
path to a custom profile JSON file with --profile.
A local real Kickstart 1.3 ROM can also be used for testing. Place it at
CopperScreen\ROM\Kickstart_13.rom, or pass a path with --kickstart-rom.
ROM files are local-only and should not be committed.
Available startup profiles:
| Profile config | Memory | Kickstart source |
|---|---|---|
vanilla-copperstart |
512 KB chip RAM | CopperStart 1.3 |
expanded-copperstart |
512 KB chip RAM + 512 KB pseudo-fast at $C00000 |
CopperStart 1.3 |
vanilla-kickstart13 |
512 KB chip RAM | real Kickstart 1.3 ROM |
expanded-kickstart13 |
512 KB chip RAM + 512 KB pseudo-fast at $C00000 |
real Kickstart 1.3 ROM |
Examples:
dotnet run --project .\CopperScreen -- --profile vanilla-copperstart "path\to\disk.adf"
dotnet run --project .\CopperScreen -- --profile expanded-kickstart13 --kickstart-rom ".\CopperScreen\ROM\Kickstart_13.rom" "path\to\disk.zip"
dotnet run --project .\CopperScreen -- --profile ".\CopperScreen\Profiles\expanded-copperstart.json" "path\to\disk.adf"The ROM-backed profiles are still an emulator bring-up path; CopperStart remains the default for day-to-day disk testing.
CopperScreen can optionally mix user-supplied mechanical floppy drive sounds into
the host audio output. These sounds are a front-end feature only: they are mixed
after Paula audio, and are not referenced by CopperMod.Amiga or the CUST
player. No sound samples are bundled or committed.
Sound packs live under CopperScreen\Sounds\Floppy\<pack-name> by default:
CopperScreen/
Sounds/
Floppy/
default/
motor-start.*
motor-loop.*
motor-stop.*
disk-insert.*
disk-eject.*
step/
step-01.*
step-02.*
seek/
seek-01.*
seek-02.*
File extensions are ignored when matching the stems above. Samples are decoded
with NAudio, so supported formats depend on the host. In samples mode,
missing individual files are fine; a missing or empty pack disables drive sounds
with a status message.
Profile configuration:
"audio": {
"floppyDriveSounds": {
"enabled": false,
"mode": "synthetic",
"soundPack": "default",
"volume": 0.25
}
}Command-line overrides:
dotnet run --project .\CopperScreen -- --floppy-sounds on --floppy-sound-mode synthetic --floppy-sound-volume 0.25 "path\to\disk.adf"
dotnet run --project .\CopperScreen -- --floppy-sounds on --floppy-sound-mode samples --floppy-sound-pack default --floppy-sound-volume 0.25 "path\to\disk.adf"mode defaults to synthetic when drive sounds are enabled. Synthetic mode
does not require sample files. samples mode uses soundPack, which resolves
as CopperScreen\Sounds\Floppy\<name> unless it is an absolute path or an
explicit relative path such as .\MyPack.
The static project website lives in docs. GitHub Pages deploys it through
.github/workflows/pages.yml on pushes to main and manual workflow runs.
CopperMod.Tools renders supported modules to files without opening the player:
dotnet run --project .\CopperMod.Tools -- render "path\to\tune.mod" --out tune.wav --seconds 30
dotnet run --project .\CopperMod.Tools -- render "path\to\tune.sid" --out tune.pcm --seconds 30
dotnet run --project .\CopperMod.Tools -- render "path\to\tune.sid" --out tune.mp3 --seconds 30 --mp3-bitrate 192WAV output is 32-bit float. PCM output is raw interleaved little-endian Float32. MP3 output uses the Windows Media Foundation encoder through NAudio.Wasapi. See CopperMod.Tools README for the full command reference.
CopperMod and CopperScreen are released separately. Each release script publishes
a Windows self-contained zip and a portable .NET zip that can be run with
dotnet CopperMod.dll or dotnet CopperScreen.dll.
.\scripts\release\publish-coppermod.ps1 -Version 1.0.0
.\scripts\release\release-coppermod.ps1 -Version 1.0.0
.\scripts\release\publish-copperscreen.ps1 -Version 1.0.0
.\scripts\release\release-copperscreen.ps1 -Version 1.0.0The publish scripts strip .pdb and .xml files before zipping. CopperMod
releases use tags like coppermod-v1.0.0; CopperScreen releases use tags like
copperscreen-v1.0.0.
The release scripts use GitHub CLI (gh) when it is installed. Without gh,
run the release script with -TagOnly, then create the GitHub release manually
and upload the generated zip files plus SHA256SUMS.txt.
CopperMod- terminal player application.CopperMod.Abstractions- shared playback interfaces.CopperMod.Rendering- shared format registration and offline rendering helpers.CopperMod.Tools- offline render/export utility.CopperMod.Med- MED / OctaMED backend.CopperMod.ProTracker- ProTracker MOD backend.CopperMod.Sid- PSID / RSID backend.Copper68k- reusable Motorola 68000-family CPU emulation core.Copper6510- reusable MOS 6510 CPU emulation core.CopperDisk- managed Amiga ADF / IPF disk image library.CopperMod.Amiga- shared Amiga 500 emulation core.CopperScreen- Avalonia Amiga 500 emulator front-end.