This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Furnace is a multi-system chiptune tracker - music production software for creating music using vintage sound chips from retro computers and game consoles. It supports over 200+ sound chip configurations and can load/save various tracker formats including DefleMask (.dmf).
Furnace uses CMake as its build system. The project requires C++14 and has extensive platform support (Windows, macOS, Linux).
# Initial setup
git clone --recursive https://github.com/tildearrow/furnace.git
cd furnace
# Standard build process
mkdir build
cd build
cmake ..
make # or 'ninja' on Windows/MSYS2- Windows (MSYS2/MinGW64): Use
ninjainstead ofmake, ensure MINGW64 environment (NOT UCRT64) - Windows (Visual Studio): Use
msbuild ALL_BUILD.vcxprojor open the generated solution - macOS: Can use Xcode generator with
cmake -G Xcode ..
BUILD_GUI=ON/OFF- Build GUI tracker vs headless player onlyUSE_RTMIDI=ON/OFF- Include MIDI supportWARNINGS_ARE_ERRORS=ON/OFF- Treat warnings as errors (recommended for development)SYSTEM_*options - Use system libraries instead of vendored ones
After initial CMake configuration, you only need to run the build command (make/ninja/msbuild) for subsequent builds.
The project includes a delta-based audio regression testing system:
./test/furnace-test.shThis script:
- Renders all test songs in
test/songs/to WAV files - Calculates audio deltas compared to previous test run
- Verifies deltas are within acceptable thresholds
Requires GNU parallel and ffmpeg. The test compares rendered audio output to detect playback regressions.
Engine (src/engine/) - The heart of Furnace
engine.cpp/h- Main engine class (DivEngine) coordinating all subsystemsplayback.cpp- Pattern playback and timing logic (131KB - complex!)song.cpp/h- Song data structure and managementdispatch.h- Command interface for chip communication (DIV_CMD_*)platform/- Sound chip implementations (70+ files, one per chip/chip family)
Platform Dispatch System Each sound chip has a "platform" implementation (DivPlatform*) that:
- Handles note on/off, volume, panning via dispatch commands
- Manages chip-specific registers and state
- Provides audio output through acquire() method
- Located in
src/engine/platform/
GUI (src/gui/) - ImGui-based interface
- Large number of specialized files for different windows/features
gui.cpp(not shown but exists) - Main GUI coordinator- Font files embedded as C++ arrays (font_*.cpp)
- Pattern editor, instrument editor, mixer, etc. as separate components
Audio Backend (src/audio/) - Platform audio I/O
- Supports multiple backends: SDL, PortAudio, JACK, ASIO, Pipe
taAudio.h- Abstract audio interface
File Operations (src/engine/fileOps/ and src/engine/)
- Module loading/saving spread across multiple files
- Format compatibility is CRITICAL - see contribution guidelines
fileOpsIns.cpp- Instrument file operationsvgmOps.cpp,wavOps.cpp- Export operations
- DivEngine - Central coordinator managing song, instruments, playback, audio output
- DivDispatch - Abstract interface for sound chip implementations
- DivInstrument - Instrument definition with chip-specific parameters
- DivSample - PCM sample data and metadata
- DivWavetable - Wavetable data for wavetable synthesis
- DivSong - Complete song data including patterns, orders, subsongs
User Input (GUI/CLI) → DivEngine → Playback Engine → DivDispatch (per chip) → Audio Backend → Output
↓
Pattern Data
Instruments
Samples
Critical Rules:
- Two spaces for indentation - NO TABS
- Modified 1TBS brace style
- No spaces in function calls:
foo(a,b)notfoo( a, b ) - C++ pointer style:
void* variablenotvoid *variable - Always specify signedness for char types except for C strings
- Prefer
NULLovernullptr - Use
Stringtypedef forstd::string(from ta-utils.h)
Type Preferences:
bool,signed char,unsigned char(8-bit)short,unsigned short(16-bit)int,unsigned int(32-bit)float(32-bit),double(64-bit)int64_t,uint64_tfor 64-bit (avoid when possible, target is 32-bit)size_tfor sizes
Compatibility Requirements:
- NEVER break file format compatibility without extreme care
- NEVER bump version number in DIV_ENGINE_VERSION
- DO NOT modify loadFur/saveFur without deep understanding
- New fields must be added at END of blocks for forward compatibility
- Test with old songs after playback changes
- Do not use
#pragma once(use include guards) - Do not use
gotounless absolutely necessary - Default case must be LAST in switch statements
Additional Guidelines:
- Use safe C string operations only (snprintf, strncpy, strncat)
- Always use decimal with
fsuffix for floats:1.0fnot1 - Only use
autowhen necessary
-
Adding a New Sound Chip:
- Create platform implementation in
src/engine/platform/ - Inherit from DivDispatch, implement required methods
- Add chip definition to
sysDef.cpp - Add to CMakeLists.txt
- Create platform implementation in
-
Modifying Playback:
- Main logic is in
src/engine/playback.cpp(massive file) - Always test with old songs for regression
- May require adding compatibility flags
- Main logic is in
-
GUI Changes:
- Find relevant file in
src/engine/gui/ - ImGui is the UI framework
- GUI coordinates with engine via DivEngine interface
- Find relevant file in
-
Adding Effects/Commands:
- Add to DivDispatchCmds enum in
dispatch.h - Update cmdName[] array in
playback.cpp - Implement in relevant platform files
- Add to DivDispatchCmds enum in
Located in extern/ directory (git submodules):
- SDL2 - Windowing and audio
- ImGui - GUI framework
- Various sound chip emulation cores (Nuked, MAME, ymfm, etc.)
- Audio codec libraries (FLAC, Vorbis, Opus, LAME)
- libsndfile - Audio file I/O
Important: Always clone with --recursive to fetch submodules.
Version 0.6.8 (dev244) as of engine.h. Project targets version 0.7 with features listed in TODO.md.