This file provides guidance when working with code in this repository.
bin/alsdiff.ml- Main executable entry pointlib/- Core library modules organized into sublibraries:lib/base/- Base functionality modules:xml.ml- XML parsing and data structuresupath.ml- XPath-like query language for XMLfile.ml- File handling and .als file decompressionequality.ml- Equality checking utilitiesdiff.ml- List diffing algorithms
lib/live/- Ableton Live specific modules:automation.ml- Automation envelope handlingclip.ml- Clip and mixer functionalitytrack.ml- Track handling and management (contains all track modules: Routing, RoutingSet, Send, Mixer, MidiTrack, AudioTrack, MainMixer, MainTrack)device.ml- Device functionality (includes plugin, regular, group devices, and Max for Live)liveset.ml- Live set management
lib/output/- Output formatting:output.ml- Output interface definitionstext_renderer.ml- Plain text output renderingstats_renderer.ml- Statistics summary output renderingview_model.ml- View model for output formatting
test/- Test suites (all use specific module opens for cleaner code):test_upath.ml- Tests for XPath-like functionalitytest_xml.ml- Tests for XML parsingtest_wildcard.ml- Tests for wildcard matchingtest_wildcard_debug.ml- Debug tests for wildcard matchingtest_complex.ml- Complex integration teststest_audio_clip.ml- Tests for audio clip functionalitytest_midi_clip.ml- Tests for MIDI clip functionalitytest_midi_track.ml- Tests for MIDI track functionalitytest_audio_track.ml- Tests for audio track functionalitytest_main_track.ml- Tests for MainTrack (singleton master output track)test_device.ml- Tests for device functionalitytest_plugin_device.ml- Tests for plugin device functionalitytest_group_device.ml- Tests for group device functionalitytest_m4l_device.ml- Tests for Max for Live device functionalitytest_real_devices.ml- Tests for real device implementationstest_diff_automation.ml- Tests for diffing automation envelopestest_diff_list.ml- Tests for list diffing functionalitytest_diff_audio_clip.ml- Tests for audio clip diffingtest_diff_midi_clip.ml- Tests for MIDI clip diffingtest_diff_mixer.ml- Tests for mixer diffing functionalitytest_diff_device.ml- Tests for device diffing functionalitytest_diff_track.ml- Tests for track diffing functionalitytest_clip_patch.ml- Tests for clip patching functionalitytest_liveset.ml- Tests for liveset functionalitytest_regex_match.ml- Tests for regex matching functionalitytest_view_model.ml- Tests for view model functionalitytest_detail_config_json.ml- Tests for JSON config handlingtest_text_renderer.ml- Tests for text renderertest_stats_renderer.ml- Tests for statistics rendererutils.ml- Shared test utilities
All dependencies with their repositories:
| Dependency | Version | Description | Repository |
|---|---|---|---|
ocaml |
>= 5.3.0 | OCaml compiler | https://ocaml.org |
xmlm |
- | XML parsing | https://github.com/dbuenzli/xmlm |
camlzip |
- | Gzip decompression for .als files | https://github.com/xavierleroy/camlzip |
angstrom |
- | Parser combinators for Upath | https://github.com/inhabitedtype/angstrom |
eio |
- | Effects-based IO | https://github.com/ocaml-multicore/eio |
eio_main |
- | EIO main | https://github.com/ocaml-multicore/eio |
alcotest |
- | Testing framework | https://github.com/mirage/alcotest |
re |
- | Regular expression library | https://github.com/ocaml/ocaml-re |
cmdliner |
>= 2.0.0 | Command line interface library | https://github.com/dbuenzli/cmdliner |
ppx_deriving |
- | PPX extension for deriving equality functions | https://github.com/ocaml-ppx/ppx_deriving |
ppx_deriving_yojson |
- | PPX extension for Yojson serialization | https://github.com/ocaml-ppx/ppx_deriving_yojson |
ppx_deriving_jsonschema |
- | PPX extension for JSON schema generation | https://github.com/ahrefs/ppx_deriving_jsonschema |
jsonschema |
- | JSON schema validation | https://github.com/ocaml-community/jsonschema |
fmt |
- | Pretty-printing | https://github.com/dbuenzli/fmt |
ptime |
- | Time handling | https://github.com/dbuenzli/ptime |
yojson |
- | JSON parsing and serialization | https://github.com/ocaml-community/yojson |
This is a Git helper tool for Ableton Live Set (.als) files. The core functionality:
- File Handling: Decompress .als files (which are gzipped XML)
- XML Processing: Parse and navigate XML structure of Live sets
- Upath: Custom XPath-like query language for finding elements in XML
- Diffing: Compare Live set objects to detect changes with advanced algorithms
- Patch Management: Handle patches and modifications
- Output Formatting: Format and display results
The Upath module provides a subset of XPath functionality with support for:
- Tag names with attributes (
tag@attr="value") - Indexing with optional tag matching (
[0],[1],tag[0],tag[1]) - Wildcards (
*,**) - Path navigation (
/tag1/tag2)
The Diff module implements multiple diffing algorithms:
- Ordered diffing for sequential data
- Myers O(ND) algorithm for optimal diffing performance
- Specialized diffing for automation envelopes in Live sets
- Structured diffing with patch generation for complex data types
All track-related modules are consolidated in lib/live/track.ml:
- Routing & RoutingSet: Handle audio/MIDI input/output routing configuration
- Send: Track-to-track send routing with amount parameters
- Mixer: Standard track mixer with volume, pan, mute, solo, and sends
- MidiTrack: MIDI tracks with clips, automations, devices, mixer, and routings
- AudioTrack: Audio tracks with clips, automations, devices, mixer, and routings
- MainMixer: Extends Mixer with global parameters (tempo, time signature, crossfade, global groove)
- MainTrack: Singleton master output track (no
idfield - uses singleton pattern)has_same_id _ _ = true- always returns trueid_hash _ = Hashtbl.hash 0- constant hash- No ID validation in diff function
The project includes comprehensive support for Ableton Live devices:
- Device Types: Regular devices, Plugin devices (VST2, VST3, AUv2), Group devices, and Max for Live devices
- Device Architecture: Consolidated in device.ml with unified device type system
- Device Mapping: Type-safe mapping from XML to OCaml data structures
- Real Device Support: Support for actual Ableton Live device implementations
- Test Coverage: Extensive test suite covering all device types and edge cases
- Diffing Support: Advanced diffing algorithms for all device types with proper patch generation
The project is organized into four main libraries:
- alsdiff_base (
lib/base/) - Core functionality - alsdiff_live (
lib/live/) - Ableton Live specific types and logic - alsdiff_output (
lib/output/) - Output formatting
When working with the libraries, use specific module opens for cleaner code:
(* Base modules *)
open Alsdiff_base.Xml
open Alsdiff_base.Upath
open Alsdiff_base.Diff
(* Live modules *)
open Alsdiff_live.Automation
open Alsdiff_live.Clip
open Alsdiff_live.Track
open Alsdiff_live.Device
open Alsdiff_live.Liveset
(* Track submodule access (from track.ml) *)
open Alsdiff_live.Track.Routing
open Alsdiff_live.Track.Mixer
open Alsdiff_live.Track.MidiTrack
open Alsdiff_live.Track.AudioTrack
open Alsdiff_live.Track.MainTrack
(* Output modules *)
open Alsdiff_output.Text_rendererThis allows you to write:
Automation.tinstead ofAlsdiff_live.Automation.Automation.tXml.read_fileinstead ofAlsdiff_base.Xml.read_fileMainTrack.tinstead ofAlsdiff_live.Track.MainTrack.t
Note: MainTrack is a singleton (master output track) and does not have an id field. It uses singleton pattern with has_same_id _ _ = true and id_hash _ = Hashtbl.hash 0.
This is an OCaml project using Dune build system.
dune build- Build the projectdune runtest- Run all testsdune runtest --force- Force rerun all testsdune exec alsdiff- Run the main executabledune exec test/test_upath.exe- Run specific testtest/test_upath.ml(Upath tests)
dune build @fmt- Format codedune promote- Promote generated filesdune clean- Clean build artifactsdune utop- Load this library into Utop REPLdune utop . -- -emacs- Load this library into Utop REPL for Emacs utop-mode
To inspect code after PPX rewriting (e.g., to see generated equality functions from [@@deriving eq]):
dune describe pp lib/live/device.ml- Show PPX-expanded code for a specific file
alsdiff FILE1.als FILE2.als- Compare two ALS files--mode tree|stats- Output mode: hierarchical tree (default) or stats summary--preset PRESET- Use output preset (compact, composer, full, inline, mixing, quiet, verbose)--config FILE- Load configuration from JSON file--dump-preset PRESET- Dump preset configuration as JSON to stdout--dump-schema- Dump JSON schema for configuration to stdout--validate-config FILE- Validate a config file against schema--git- Git external diff driver mode (exit code 0 = no changes, 1 = changes)--prefix-added/removed/modified/unchanged- Custom change prefixes--note-name-style Sharp|Flat- Note naming convention--max-collection-items N- Limit collection output size
Library code (lib/): Use opens at top of files for cleaner code
open Alsdiff_base
open Alsdiff_base.Diff
open Alsdiff_live
open Alsdiff_outputTest code (test/): Use specific opens
open Alsdiff_base.Xml
open Alsdiff_base.Upath
open Test_utils.UtilsFor submodules (e.g., from lib/live/track.ml):
open Alsdiff_live.Track.Routing
open Alsdiff_live.Track.Mixer
open Alsdiff_live.Track.MidiTrack- Line length: 100 characters
- Format command:
dune build @fmt - Configured in
.ocamlformat- do not modify without understanding impact - Use functional style, avoid mutable state
- Always include PPX derives:
[@@deriving eq|yojson|jsonschema] - Use
[@@deriving eq]for equality checking - Use phantom types for type safety (e.g.,
type atomic,type structured) - Keep type definitions concise with inline comments
- Modules:
module Fooinfoo.ml(standard OCaml convention) - Functions: snake_case for multi-word names (e.g.,
get_attr,parse_route_type) - Types: PascalCase, module-specific suffixes for variants (e.g.,
route_type,atomic_patch) - Record fields: snake_case
- Exception types: CamelCase with
exceptionkeyword (e.g.,exception Xml_error of t * string)
- Define custom exceptions:
exception Xml_error of t * string - Use
raise (Exception_name (context, "message"))pattern - Provide descriptive error messages with context
- Use
failwithfor programmer errors (e.g., type mismatches) - Use Option types (
get_attr_opt) for optional values
match xml with
| Element { name; childs; _ } -> (* use name and childs *)
| Data _ as xml -> raise (Xml_error (xml, "Cannot get children from Data node"))- Use
List.map,List.filter,List.iterfor transformations - Use
List.sortwithString.comparefor consistent ordering - Prefer
Option.bindover manualmatchfor option chaining - Use
Fiber.pairfor parallel operations (Eio concurrency)
- Tests in
test/directory with patterntest_<module>.ml - Use Alcotest framework:
Alcotest.check,let test_cases = [...] - Define testable types:
let foo_testable = Alcotest.(pair string int) - Test helpers in
test_utilsmodule - Keep tests focused and independent
MainTrack is a singleton (master output track):
- No
idfield has_same_id _ _ = trueid_hash _ = Hashtbl.hash 0- Skip ID validation in diff functions
- Use
Eio_main.runin entry points - Domain manager:
Eio.Stdenv.domain_mgr env - Parallel work:
Eio.Domain_manager.run domain_mgr (fun () -> ...) - Preserve
Eio_main.runstructure when modifying parallel workloads
- Run
dune buildanddune runtestafter behavioral changes - Add focused tests in
test/for new functionality - Follow existing patterns for similar constructs
- Use
[@@deriving ...]annotations - Format code with
dune build @fmtbefore committing - Use
dune describe ppto inspect PPX output if needed
- Modify code in
plugins/without explicit instruction - Remove
[@@deriving ...]annotations without understanding PPX impact - Use mutable state or imperative patterns
- Add code comments unless explicitly requested
- Change
.ocamlformatconfiguration - Break singleton pattern for
MainTrack
Follow the Conventional Commits specification: https://www.conventionalcommits.org/en/v1.0.0/ It is recommended to use a 1-3 line summary and list the specific changes.