STEM

A workspace for the passes of a song - demos, vocals, mixes - with the reason each one changed kept on the version where it happened.

Type
Music App
Role
Creative Technologist
Built
-
Updated
-
Source
GitHub

Tech stack

  • Next.js
  • React
  • TypeScript
  • Web Audio
  • Supabase
  • AI

Songs aren’t created in one file. They’re created through hundreds of decisions.

Every version, and why it changed.

stem.chiradeep.me
stem.chiradeep.me

Seven files, no reason

  • demo.wav
  • demo2.wav
  • new chorus.wav
  • final.wav
  • final-final.wav
  • actual-final.wav

The folder can count them. It cannot say why the second synth left, or why a vocal stayed when the timing was wrong and the feeling was right.

STEM keeps the song as the unit. Every bounce stays, in order, with the sentence written on the version where the decision happened.

The song is the unit

Ideas, instrumentals, vocals, mixes, masters, references, and decisions all belong to one song. Files are children of the song, not the other way around.

Song
├── Ideas
├── Instrumentals
├── Vocals
├── Mixes
├── Masters
├── References
└── Decisions

The note stays on the version

Nothing is overwritten. v01 is the demo. v03 is the chorus rewrite. The reason lives on the version where it happened: the second synth left because the chorus felt crowded, or this vocal stayed because the feeling was right and the timing was not.

lib/songs/version.ts
type Version = {  id: string  songId: string  label: string // "v03 - chorus rewrite"  audioId: string  decision: string | null} // A waveform says what happened.// decision says why.

Analysis is not the producer

The model can compare takes, look at pitch and timing, and answer what changed between version 3 and version 5. It can flag a crowded section.

It does not write the song. The musician remains the authority. The workspace is a desk, not a feed.

The hard part

A waveform is not a reason

Storing audio is ordinary. The hard part is keeping the creative context: why this pass replaced the last one, and which take was kept for the feeling rather than the timing.

Solution

Every version can carry a decision. Playback, the waveform, and the note sit in the same view. History is kept, including the passes that will never be released.

Trade-offs

DecisionChoiceWhy
VersioningKeep every passA tidy folder is how the reason disappears.
AICompare and describeAssistance is not authorship.
InterfaceA workspaceNot a social feed of bounces.
OrganizationSong-centricFiles belong to the song.

What I’d change

  • A path into the DAW, and real stem-level files.
  • Deeper waveform editing and collaborative sessions.
  • A phone companion for ideas caught away from the desk.

On the session

What happens to final-final.wav?

It becomes a version with a label, in order, under the song. The earlier demo is still there. Saving a new bounce never deletes the previous one.

Where do I write why I changed the chorus?

On that version. The waveform shows what happened. The decision is the line next to it, and it does not float off into a notes app.

Can it produce the next chorus for me?

It can tell you what moved between version 3 and version 5, and it can point at a section that feels crowded. The musician is still the one who decides. The model is not the producer.

Have an idea...

Have something to build.