Skip to main content
Glama
dastjead
by dastjead
README.md
# Strudel Console

> **[English](README.en.md)** | 한국어

Strudel 기반 TUI 음악 작곡 도구 + MCP 서버.
터미널에서 라이브 코딩하거나, Claude Code 같은 AI 에이전트를 통해 음악을 만들 수 있습니다.

![Strudel Console TUI](docs/screenshot-tui.png)

## 설치 및 실행

```bash
npm install
npm run build
```

### TUI 모드 (기본)

```bash
npm start
# 또는
npm run tui
```

### MCP 서버 모드

```bash
npm run mcp
```

Claude Code의 `settings.json`에 등록:

```json
{
  "mcpServers": {
    "strudel-console": {
      "command": "node",
      "args": ["--experimental-specifier-resolution=node", "/path/to/strudel-console/dist/mcp/server.js"]
    }
  }
}
```

---

## MCP 서버 스펙

Transport: **stdio** | Protocol: MCP | Version: `0.1.0`

### 도구 (Tools)

#### Playback

| 도구 | 설명 | 파라미터 |
|------|------|----------|
| `evaluate` | Strudel 패턴 코드를 평가하고 즉시 재생 시작 | `code` (string, 필수) |
| `start` | 현재 패턴 재생 시작/재개 | — |
| `stop` | 재생 중지 | — |
| `toggle` | 재생/중지 토글 | — |
| `set_bpm` | BPM 설정 (기본 120) | `bpm` (number, 양수) |
| `get_state` | 현재 상태 조회 (재생 여부, 코드, 에러 등) | — |

#### Samples

| 도구 | 설명 | 파라미터 |
|------|------|----------|
| `load_samples` | 샘플/뱅크 로드 | `source` (string) — `github:user/repo`, 로컬 경로, 또는 URL |

#### Patterns

| 도구 | 설명 | 파라미터 |
|------|------|----------|
| `save_pattern` | 패턴을 `~/.strudel-console/patterns/`에 저장 | `name` (string), `code` (string), `bpm` (number, 선택) |
| `load_pattern` | 저장된 패턴 불러오기 | `name` (string) |
| `list_patterns` | 저장된 패턴 목록 조회 | — |

#### Multi-Track

| 도구 | 설명 | 파라미터 |
|------|------|----------|
| `add_track` | 새 트랙 추가. 모든 활성 트랙은 `stack()`으로 동시 재생 | `name` (string, 선택), `code` (string, 선택) |
| `evaluate_track` | 트랙의 패턴 코드를 업데이트하고 재컴파일 | `code` (string), `track_index` (int, 1-based, 선택 — 생략 시 활성 트랙) |
| `remove_track` | 트랙 삭제 | `track_index` (int, 1-based) |
| `mute_track` | 트랙 뮤트 토글 | `track_index` (int, 1-based) |
| `solo_track` | 트랙 솔로 토글. 솔로 트랙이 있으면 솔로만 재생 | `track_index` (int, 1-based) |
| `set_track_gain` | 트랙 볼륨 설정 | `track_index` (int, 1-based), `gain` (number, 0.0–1.0) |
| `list_tracks` | 전체 트랙 목록 + 상태 (이름, 뮤트, 솔로, 게인, 코드) | — |

#### Mixer

| 도구 | 설명 | 파라미터 |
|------|------|----------|
| `set_master_gain` | 마스터 출력 볼륨 설정 (전 트랙 적용) | `gain` (number, 0.0–1.0) |
| `list_effect_presets` | 이펙트 프리셋 목록 조회 | — |

사용 가능한 이펙트 프리셋:

| 프리셋 | 이펙트 체인 |
|--------|------------|
| `clean` | (없음) |
| `lofi` | `.lpf(800).gain(0.8)` |
| `ambient` | `.room(0.6).delay(0.4).gain(0.7)` |
| `dark` | `.lpf(400).room(0.3).gain(0.9)` |
| `bright` | `.hpf(300).lpf(8000).gain(0.9)` |
| `tape` | `.lpf(3000).room(0.2).delay(0.15).gain(0.85)` |

#### Render

| 도구 | 설명 | 파라미터 |
|------|------|----------|
| `render_to_file` | 패턴을 WAV 파일로 렌더링 (OfflineAudioContext) | `code` (string, 선택), `cycles` (int, 1–64, 기본 8), `bpm` (number, 선택), `filename` (string, 선택) |

출력 경로: `~/.strudel-console/renders/`

#### AI Composition

| 도구 | 설명 | 파라미터 |
|------|------|----------|
| `analyze_pattern` | 패턴의 음악적 속성 분석 (키, 스케일, 음역, 밀도) | `code` (string), `cycles` (int, 1–16, 기본 4) |
| `load_genre_preset` | 장르 프리셋 로드 — 트랙 + BPM 자동 설정 후 재생 시작 | `genre` (string) |
| `list_genre_presets` | 장르 프리셋 목록 + 설명 조회 | — |

사용 가능한 장르 프리셋:

| 장르 | BPM | 트랙 수 | 설명 |
|------|-----|---------|------|
| `lofi` | 75 | 4 | Chill lo-fi beats with jazzy chords |
| `techno` | 130 | 4 | Driving four-on-the-floor with acid bassline |
| `ambient` | 60 | 3 | Slow evolving pads with reverb |
| `house` | 124 | 5 | Classic house groove with organ stabs |
| `dnb` | 174 | 3 | Fast breakbeat with rolling bass |
| `jazz` | 110 | 3 | Swing feel with ii-V-I progression |

### 리소스 (Resources)

| URI | 설명 |
|-----|------|
| `strudel-console://guide` | Strudel 패턴 작성 가이드 (미니 노테이션, 이펙트, 멀티트랙 워크플로우) |
| `strudel-console://music-theory` | 음악 이론 레퍼런스 (스케일, 코드 진행, 리듬 패턴, 인터벌) |

---

## 워크플로우 예시

### 1. 단일 패턴 재생

```
evaluate({ code: 'note("c4 e4 g4 b4").sound("sine")' })
set_bpm({ bpm: 90 })
stop()
```

### 2. 멀티트랙 작곡

```
add_track({ name: "drums", code: 's("bd sd hh sd")' })
add_track({ name: "bass", code: 'note("c2 e2 g2 e2").sound("sawtooth").lpf(400)' })
evaluate_track({ code: 's("bd sd [~ bd] sd")', track_index: 1 })
mute_track({ track_index: 2 })          // 베이스 뮤트
set_track_gain({ track_index: 1, gain: 0.8 })
```

### 3. 장르 프리셋 → 커스텀

```
load_genre_preset({ genre: "lofi" })     // 4트랙 + 75 BPM 세팅
list_tracks()                            // 현재 트랙 확인
evaluate_track({ code: 's("bd ~ [bd sd] ~")', track_index: 1 })  // 드럼 수정
set_master_gain({ gain: 0.7 })
```

### 4. 분석 → 렌더링

```
analyze_pattern({ code: 'note("c4 e4 g4 b4").sound("sine")', cycles: 4 })
render_to_file({ code: 'note("c4 e4 g4 b4").sound("sine")', cycles: 16, bpm: 90, filename: "melody" })
```

---

## 에러 처리

모든 도구는 실패 시 `isError: true`와 함께 에러 메시지를 반환합니다.

| 상황 | 에러 예시 |
|------|----------|
| 잘못된 Strudel 구문 | `Error: unexpected token ...` |
| 존재하지 않는 트랙 인덱스 | `Error: track 5 does not exist` |
| 존재하지 않는 장르 | `Unknown genre. Available: lofi, techno, ambient, house, dnb, jazz` |
| 렌더링할 패턴 없음 | `Error: no pattern to render. Provide code or set up tracks.` |
| 존재하지 않는 패턴 이름 | `Error: pattern not found: ...` |

---

## 기술 스택

- **엔진**: @strudel/* v1.1.0 + node-web-audio-api (IRCAM Rust 바인딩)
- **MCP**: @modelcontextprotocol/sdk (stdio transport)
- **TUI**: Ink 5.x + React 18
- **언어**: TypeScript (ESM)

---

## 라이선스

이 프로젝트는 [GNU Affero General Public License v3.0 or later](LICENSE) 하에 배포됩니다.

[Strudel](https://github.com/tidalcycles/strudel) (AGPL-3.0-or-later) 기반 파생 저작물입니다.