On the night of 24 August, I asked Olivia, an AI music tutor, whether she could write a MIDI file for me. She sent eight bars in D major, with three beats to a bar, at sixty beats a minute. The file arrived encoded as text in a Discord message. It is still in the repository as olivia.mid.
She asked whether I had listened. I had not; it was nearly midnight. The next morning I went looking for a lightweight MIDI player, something that would let me open the file and hear it without starting a full music workstation.
The file it started with
Listen to the original eight bars.
D major, three beats to a bar, sixty beats a minute.
That search became Battuta. It now gives an agent commands to inspect a MIDI file, make a specific change, compare the result with the original, and play it. The small melody became a file the tool could read and edit, and a fixture against which its behaviour could be checked.
A file to keep working on
The first requirement was playback. Then I wanted the player to be usable from an agent’s command line. Once the agent could work with the file, a more interesting activity came into view: take apart a few bars, change something, and hear the difference.
MIDI makes that activity possible because it holds instructions. A note has a pitch, a starting time, a duration and a strike velocity. Those values can be inspected and changed individually. A synthesiser turns the instructions into sound.
I built a Rust core around those operations, with a command-line program called mid. Inspection gives an agent identifiers for the notes in the file. An edit request names particular notes and the changes to make. Applying it produces another MIDI file. A comparison describes the changes, and playback gives the result something a written report cannot supply: sound.
That is a workable scale for a music lesson. An intention such as “this part feels too crowded” can lead to a specific experiment in a few bars. Translating the reaction into a proposed change belongs in the conversation; the tool supplies the means to carry it out and examine the result.
Keeping the original gives an experiment somewhere to return
I made each edit write a new file. The previous one remains available to compare or return to. Version names and storage belong to the filesystem; Battuta does not manage a separate history of the piece.
This gives a small change a useful shape. To try a different opening pitch, an agent can name the opening note and transpose it. To change its strike velocity, it can alter that value. The request specifies the experiment; the resulting file and comparison show what was produced. Other parts of the piece remain outside the request.
Local editing was a deliberate choice. I wanted the work to accumulate: a melody could survive a discussion about its accompaniment, and a change could remain available even if the next attempt went elsewhere. A finished experiment would leave another concrete version of the same piece.
Bringing a few bars into reach
Selecting a passage is part of making that scale practical. Both inspection and playback accept a bar range, so the same stretch can be read and auditioned. Playback builds a temporary MIDI passage for the synthesiser and removes it when the command finishes.
The passage needs some context from before its first bar. An instrument may have been selected earlier, for example. The implementation carries supported settings into the passage so that starting later in the file does not simply discard them. Its selection rule follows notes that start inside the range and keeps their full written lengths; a note held over from before the range is excluded. That matters when judging a passage whose accompaniment was already sounding.
Playback also names the soundfont used to turn the MIDI instructions into audio. The musical file and the apparatus used to hear it have different jobs. Keeping both referable gives a comparison a stated listening setup.
Learning through a change I can make
I was learning Rust and music through the same project. The tool gave ownership, data modelling and command-line design a concrete job. The musical side gave me something to ask of the implementation beyond whether it compiled: could I locate a few notes, change them, and have another file ready to hear?
The original eight bars still give that question a place to start. An agent can inspect the opening A4, lower it to G4 and produce a comparison identifying that change at bar 1 beat 1. The old file remains alongside the new one. I can bring both to the next listening decision.
The original file and implementation record
The account of the first eight bars comes from the project’s origin record. The original MIDI file remains in the repository.
The initial command loop and passage-playback implementation document the capabilities described here. This account describes building the tool; it does not reconstruct a first listening response or claim that a particular edit improved the music.