Carnatic AI Music Generator
Full-stack AI-powered Carnatic music composition tool. FastAPI backend with raga definitions (Shankarabharanam, Kalyani, Mohanam, Hamsadhwani), swara-to-MIDI mapping, melody generator, 10 preset tunes, and MIDI file construction (mido).
Role
Full-stack Developer
Team
Solo
Company/Organization
Personal Project
The Problem
Carnatic classical music has rich melodic frameworks (ragas) but no accessible browser-based tooling for generating raga-compliant melodies — ...
Musicians and learners had no way to quickly generate, hear, and download raga-based melodies with different instruments and tempos without...
Tone.js browser synthesis required distinct synth architectures per instrument to capture the characteristic timbre of classical Indian instruments...
Preset tunes like Jana Gana Mana and Vande Mataram needed to be encoded as note sequences with correct swaras, durations, and timing — no existing...
MIDI generation from raga note sequences required mapping Carnatic swara names to MIDI note numbers and constructing valid MIDI tracks with tempo,...
The Solution
Built a clean full-stack architecture separating raga/instrument definitions, melody generation, MIDI construction, presets, and API routing into...
Backend (Python 3.11 + FastAPI)
ragas.py — Defines 4 Carnatic ragas as swara (note name) sequences with octave and scale degree mappings. Shankarabharanam (equivalent to major...
instruments.py — Maps 5 instruments to MIDI program numbers: Veena (24 — Acoustic Guitar pluck approximation), Violin (40 — Violin), Flute (73 —...
generator.py — Melody generation service: takes raga name, instrument, tempo (BPM), and note length as inputs. Randomly samples notes from the...
midi_utils.py — MIDI file construction via mido: creates MidiFile with MetaMessage (tempo, time signature), adds NoteOn/NoteOff events for each...
presets.py — 10 hardcoded preset tunes encoded as note sequences: Happy Birthday, Twinkle Twinkle, Ode to Joy, Jana Gana Mana, Vande Mataram,...
main.py — FastAPI app with 7 endpoints: GET / (health), GET /ragas, GET /instruments, GET /presets, GET /presets/{id}, GET /download/{file}, POST...
Frontend (React 18 + Vite 5 + Tone.js)
App.jsx — Tab-based UI with two modes: Raga Generator (select raga, instrument, tempo, length → generate → play/download) and Preset Tunes...
Player.jsx — Tone.js playback component. Instrument-specific synth initialisation:
Veena: Tone.PluckSynth (karplus-strong string model, natural decay)
Violin: Tone.FMSynth (frequency modulation for bowed string harmonics)
Flute: Tone.FMSynth with high modulation index for breathy overtones
Piano: Tone.FMSynth with low modulation for percussive attack
Mridangam: Tone.MembraneSynth (membrane percussion model)
Schedules notes via Tone.Transport, tracks active note index for highlighting, renders progress bar with elapsed/total time.
api.js — Axios-based API client, reads VITE_API_URL from environment variables (localhost:8000 in dev, production URL in build). Typed...
Testing (36 pytest tests)
ragas.py: Valid swara sequences for each raga, aroha/avaroha completeness, swara-to-MIDI mapping correctness
instruments.py: MIDI program numbers, channel assignments, drum channel validation
presets.py: All 10 presets load, note sequences non-empty, required fields present
midi_utils.py: MIDI file construction produces valid .mid files, note events present, tempo set correctly
generator.py: Output length matches requested note count, all notes belong to specified raga's swara set
main.py (API routes): All 7 endpoints return correct status codes and response shapes
CI/CD (GitHub Actions)
Backend job: Python 3.11, install requirements.txt, run pytest (36 tests)
Frontend job: Node 20, npm install, npm run build (Vite production build check)
Runs on every push and PR to main
Design Decisions
Separated raga definitions (ragas.py), instrument mappings (instruments.py), melody generation (generator.py), MIDI construction (midi_utils.py), and...
Tone.js with instrument-specific synth architectures (PluckSynth for Veena, MembraneSynth for Mridangam, FMSynth variants for Violin/Flute/Piano)...
mido for MIDI construction over pretty-midi or music21 — mido is lightweight, pure Python, with no native dependencies. pretty-midi requires numpy...
Hardcoded preset note sequences over MIDI file parsing — encoding presets as Python note lists keeps them version-controlled, readable, and editable...
FastAPI over Flask/Django for the backend — FastAPI's automatic OpenAPI docs (/docs) are valuable for exploring the 7 endpoints during development,...
Generated MIDI files stored in generated/ (gitignored) and auto-cleaned after download — avoids unbounded disk growth in production without requiring...
Docker Compose with separate backend and frontend containers behind a shared network — allows independent service restarts, local development...
GitHub Actions with separate backend (Python 3.11 + pytest) and frontend (Node 20 + Vite build) jobs — parallel execution, clear failure attribution...
Tradeoffs & Constraints
Melody generation is rule-based (random weighted sampling from raga swara sets) rather than ML-based — produces valid raga-compliant melodies but...
Tone.js synths approximate instrument timbres in the browser but are not sample-based — PluckSynth for Veena uses karplus-strong synthesis which...
MIDI download is the primary output format — MIDI requires a player or DAW to hear. WAV/MP3 export would make compositions immediately listenable...
Presets are hardcoded in presets.py — adding new tunes requires a code change and redeploy. A database-backed preset system would allow adding tunes...
No tala (rhythm cycle) support — melodies are generated without rhythmic structure beyond note duration. Full Carnatic composition requires...
Would improve: Add Markov chain or LSTM-based melody generation for musically coherent phrases, implement tala (rhythm cycle) support, add sampled...
Outcome & Impact
Full-stack Carnatic music generation platform with raga generator (4 ragas, 5 instruments, configurable tempo and length), 10 preset tunes, Tone.js...
Backend defines 4 Carnatic ragas (Shankarabharanam, Kalyani, Mohanam, Hamsadhwani) as swara sequences with instrument-to-MIDI program mappings — ...
Tone.js playback uses instrument-specific synth architectures: PluckSynth (Veena), FMSynth (Violin, Flute, Piano), MembraneSynth (Mridangam) — ...
10 preset tunes encoded as structured note sequences: Happy Birthday, Twinkle Twinkle, Ode to Joy, Jana Gana Mana, Vande Mataram, Saare Jahan Se...
7 FastAPI REST endpoints: health check, raga list, instrument list, preset list, preset detail, MIDI file download, and POST /generate for raga-based...
36 pytest tests cover all backend modules: raga/swara validation, MIDI program mappings, preset completeness, MIDI file construction correctness,...
GitHub Actions CI/CD runs backend pytest (Python 3.11) and frontend Vite production build (Node 20) on every push and PR to main. Docker Compose...
Tech Stack
Backend: Python 3.11, FastAPI, Uvicorn
Music: mido (MIDI file construction), custom raga/swara definitions
Frontend: React 18, Vite 5, Tone.js (PluckSynth, FMSynth, MembraneSynth)
API Client: Axios (env-aware VITE_API_URL)
Testing: pytest (36 tests — ragas, instruments, presets, MIDI utils, generator, API routes)
CI/CD: GitHub Actions (Python 3.11 backend + Node 20 frontend jobs)
Infrastructure: Docker, Docker Compose
Automation: Makefile (install, run, stop, test, clean)