@ericdisero/aurora-shared 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/dist/audio/ffmpeg.d.ts +21 -0
- package/dist/audio/ffmpeg.js +112 -0
- package/dist/audio/wav.d.ts +15 -0
- package/dist/audio/wav.js +159 -0
- package/dist/config.d.ts +14 -0
- package/dist/config.js +50 -0
- package/dist/db.d.ts +3 -0
- package/dist/db.js +121 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +8 -0
- package/dist/jobs.d.ts +45 -0
- package/dist/jobs.js +220 -0
- package/dist/operations/index.d.ts +12 -0
- package/dist/operations/index.js +848 -0
- package/dist/paths.d.ts +17 -0
- package/dist/paths.js +79 -0
- package/dist/providers/mvsep.d.ts +27 -0
- package/dist/providers/mvsep.js +112 -0
- package/dist/providers/suno.d.ts +89 -0
- package/dist/providers/suno.js +309 -0
- package/dist/sidecars.d.ts +20 -0
- package/dist/sidecars.js +109 -0
- package/dist/skills/content.d.ts +1 -0
- package/dist/skills/content.js +9 -0
- package/dist/split.d.ts +24 -0
- package/dist/split.js +162 -0
- package/dist/stack.d.ts +19 -0
- package/dist/stack.js +139 -0
- package/dist/storage/assets.d.ts +30 -0
- package/dist/storage/assets.js +103 -0
- package/dist/storage/projects.d.ts +12 -0
- package/dist/storage/projects.js +85 -0
- package/dist/storage/references.d.ts +10 -0
- package/dist/storage/references.js +54 -0
- package/dist/storage/stems.d.ts +13 -0
- package/dist/storage/stems.js +41 -0
- package/dist/types.d.ts +72 -0
- package/dist/types.js +5 -0
- package/package.json +51 -0
- package/skills/aurora-cost-discipline.md +31 -0
- package/skills/aurora-music-production.md +43 -0
- package/skills/aurora-split-and-stems.md +33 -0
- package/skills/aurora-suno-prompting.md +35 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// Port of aurora/src/main/storage/projects.ts — identical DB rows + folder
|
|
2
|
+
// semantics so the app and the MCP see one library.
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { mkdir, rm } from 'node:fs/promises';
|
|
5
|
+
import { existsSync } from 'node:fs';
|
|
6
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
7
|
+
import { getDb } from '../db.js';
|
|
8
|
+
import { getProjectsDirectory } from '../paths.js';
|
|
9
|
+
function rowToProject(row) {
|
|
10
|
+
return {
|
|
11
|
+
id: row.id,
|
|
12
|
+
name: row.name,
|
|
13
|
+
dirName: row.dir_name || row.id,
|
|
14
|
+
createdAt: row.created_at,
|
|
15
|
+
updatedAt: row.updated_at
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
/** Filesystem-safe slug for human-readable project folders. */
|
|
19
|
+
export function slugify(input, max = 60) {
|
|
20
|
+
const slug = input
|
|
21
|
+
.toLowerCase()
|
|
22
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
23
|
+
.replace(/^-+|-+$/g, '')
|
|
24
|
+
.slice(0, max)
|
|
25
|
+
.replace(/-+$/g, '');
|
|
26
|
+
return slug || 'project';
|
|
27
|
+
}
|
|
28
|
+
function uniqueDirName(name) {
|
|
29
|
+
const base = slugify(name);
|
|
30
|
+
const root = getProjectsDirectory();
|
|
31
|
+
const taken = (dir) => existsSync(join(root, dir)) ||
|
|
32
|
+
Boolean(getDb().prepare('SELECT 1 FROM projects WHERE dir_name = ?').get(dir));
|
|
33
|
+
if (!taken(base))
|
|
34
|
+
return base;
|
|
35
|
+
for (let i = 2;; i++) {
|
|
36
|
+
const candidate = `${base}-${i}`;
|
|
37
|
+
if (!taken(candidate))
|
|
38
|
+
return candidate;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/** Absolute path to a project's directory. Legacy projects use their uuid dir. */
|
|
42
|
+
export function getProjectDirectory(projectId) {
|
|
43
|
+
const row = getDb().prepare('SELECT dir_name FROM projects WHERE id = ?').get(projectId);
|
|
44
|
+
return join(getProjectsDirectory(), row?.dir_name || projectId);
|
|
45
|
+
}
|
|
46
|
+
export function listProjects() {
|
|
47
|
+
const rows = getDb()
|
|
48
|
+
.prepare('SELECT id, name, dir_name, created_at, updated_at FROM projects ORDER BY updated_at DESC')
|
|
49
|
+
.all();
|
|
50
|
+
return rows.map(rowToProject);
|
|
51
|
+
}
|
|
52
|
+
export function getProject(id) {
|
|
53
|
+
const row = getDb()
|
|
54
|
+
.prepare('SELECT id, name, dir_name, created_at, updated_at FROM projects WHERE id = ?')
|
|
55
|
+
.get(id);
|
|
56
|
+
return row ? rowToProject(row) : null;
|
|
57
|
+
}
|
|
58
|
+
export async function createProject(name) {
|
|
59
|
+
const id = uuidv4();
|
|
60
|
+
const dirName = uniqueDirName(name);
|
|
61
|
+
await mkdir(join(getProjectsDirectory(), dirName), { recursive: true });
|
|
62
|
+
const now = Date.now();
|
|
63
|
+
// source/audio_path are dormant v0 columns (kept for the migration path).
|
|
64
|
+
getDb()
|
|
65
|
+
.prepare(`INSERT INTO projects (id, name, source, audio_path, gen_meta, dir_name, created_at, updated_at)
|
|
66
|
+
VALUES (?, ?, 'imported', '', NULL, ?, ?, ?)`)
|
|
67
|
+
.run(id, name.trim() || 'Untitled project', dirName, now, now);
|
|
68
|
+
return getProject(id);
|
|
69
|
+
}
|
|
70
|
+
/** Rename the project (DB name only — the on-disk folder keeps its name). */
|
|
71
|
+
export function renameProject(id, name) {
|
|
72
|
+
getDb()
|
|
73
|
+
.prepare('UPDATE projects SET name = ?, updated_at = ? WHERE id = ?')
|
|
74
|
+
.run(name.trim() || 'Untitled project', Date.now(), id);
|
|
75
|
+
return getProject(id);
|
|
76
|
+
}
|
|
77
|
+
export function touchProject(id) {
|
|
78
|
+
getDb().prepare('UPDATE projects SET updated_at = ? WHERE id = ?').run(Date.now(), id);
|
|
79
|
+
}
|
|
80
|
+
export async function deleteProject(id) {
|
|
81
|
+
const dir = getProjectDirectory(id);
|
|
82
|
+
getDb().prepare('DELETE FROM projects WHERE id = ?').run(id);
|
|
83
|
+
await rm(dir, { recursive: true, force: true }).catch(() => { });
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=projects.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ReferenceTrack } from '../types.js';
|
|
2
|
+
export declare function getReferenceDir(id: string): string;
|
|
3
|
+
export declare function listReferences(): ReferenceTrack[];
|
|
4
|
+
export declare function getReference(id: string): ReferenceTrack | null;
|
|
5
|
+
/** Add a reference row (status 'none'). `copy: false` points the row at the
|
|
6
|
+
* given path directly (project-scoped reference assets own their file). */
|
|
7
|
+
export declare function addReference(sourcePath: string, opts?: {
|
|
8
|
+
copy?: boolean;
|
|
9
|
+
}): Promise<ReferenceTrack>;
|
|
10
|
+
export declare function deleteReference(id: string): Promise<void>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// Port of aurora/src/main/storage/references.ts (userData/references instead
|
|
2
|
+
// of app.getPath).
|
|
3
|
+
import { join, basename, extname } from 'node:path';
|
|
4
|
+
import { mkdir, copyFile, rm } from 'node:fs/promises';
|
|
5
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
6
|
+
import { getDb } from '../db.js';
|
|
7
|
+
import { getReferencesDir } from '../paths.js';
|
|
8
|
+
function rowToReference(row) {
|
|
9
|
+
return {
|
|
10
|
+
id: row.id,
|
|
11
|
+
name: row.name,
|
|
12
|
+
audioPath: row.audio_path,
|
|
13
|
+
cachedCurvePath: row.cached_curve_path,
|
|
14
|
+
curveStatus: row.curve_status,
|
|
15
|
+
createdAt: row.created_at
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export function getReferenceDir(id) {
|
|
19
|
+
return join(getReferencesDir(), id);
|
|
20
|
+
}
|
|
21
|
+
export function listReferences() {
|
|
22
|
+
const rows = getDb()
|
|
23
|
+
.prepare('SELECT * FROM reference_tracks ORDER BY created_at DESC')
|
|
24
|
+
.all();
|
|
25
|
+
return rows.map(rowToReference);
|
|
26
|
+
}
|
|
27
|
+
export function getReference(id) {
|
|
28
|
+
const row = getDb().prepare('SELECT * FROM reference_tracks WHERE id = ?').get(id);
|
|
29
|
+
return row ? rowToReference(row) : null;
|
|
30
|
+
}
|
|
31
|
+
/** Add a reference row (status 'none'). `copy: false` points the row at the
|
|
32
|
+
* given path directly (project-scoped reference assets own their file). */
|
|
33
|
+
export async function addReference(sourcePath, opts = {}) {
|
|
34
|
+
const id = uuidv4();
|
|
35
|
+
const dir = getReferenceDir(id);
|
|
36
|
+
await mkdir(dir, { recursive: true });
|
|
37
|
+
const ext = extname(sourcePath) || '.wav';
|
|
38
|
+
let audioPath = sourcePath;
|
|
39
|
+
if (opts.copy !== false) {
|
|
40
|
+
audioPath = join(dir, `audio${ext}`);
|
|
41
|
+
await copyFile(sourcePath, audioPath);
|
|
42
|
+
}
|
|
43
|
+
const name = basename(sourcePath, ext) || 'Reference';
|
|
44
|
+
getDb()
|
|
45
|
+
.prepare(`INSERT INTO reference_tracks (id, name, audio_path, cached_curve_path, curve_status, created_at)
|
|
46
|
+
VALUES (?, ?, ?, NULL, 'none', ?)`)
|
|
47
|
+
.run(id, name, audioPath, Date.now());
|
|
48
|
+
return getReference(id);
|
|
49
|
+
}
|
|
50
|
+
export async function deleteReference(id) {
|
|
51
|
+
getDb().prepare('DELETE FROM reference_tracks WHERE id = ?').run(id);
|
|
52
|
+
await rm(getReferenceDir(id), { recursive: true, force: true }).catch(() => { });
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=references.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ProjectStem, StemType } from '../types.js';
|
|
2
|
+
/** Stems of one split set (an asset's). */
|
|
3
|
+
export declare function getStems(assetId: string): ProjectStem[];
|
|
4
|
+
/** All split sets in a project. */
|
|
5
|
+
export declare function getProjectStems(projectId: string): ProjectStem[];
|
|
6
|
+
/** Upsert a stem row (one per asset+stem_type — the unique index enforces it). */
|
|
7
|
+
export declare function upsertStem(params: {
|
|
8
|
+
projectId: string;
|
|
9
|
+
assetId: string;
|
|
10
|
+
stemType: StemType;
|
|
11
|
+
path: string;
|
|
12
|
+
origin: 'mvsep' | 'synthesized';
|
|
13
|
+
}): ProjectStem;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// Port of aurora/src/main/storage/stems.ts.
|
|
2
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
3
|
+
import { getDb } from '../db.js';
|
|
4
|
+
function rowToStem(row) {
|
|
5
|
+
return {
|
|
6
|
+
id: row.id,
|
|
7
|
+
projectId: row.project_id,
|
|
8
|
+
assetId: row.asset_id,
|
|
9
|
+
stemType: row.stem_type,
|
|
10
|
+
path: row.path,
|
|
11
|
+
origin: row.origin
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
/** Stems of one split set (an asset's). */
|
|
15
|
+
export function getStems(assetId) {
|
|
16
|
+
const rows = getDb()
|
|
17
|
+
.prepare('SELECT * FROM project_stems WHERE asset_id = ? ORDER BY stem_type')
|
|
18
|
+
.all(assetId);
|
|
19
|
+
return rows.map(rowToStem);
|
|
20
|
+
}
|
|
21
|
+
/** All split sets in a project. */
|
|
22
|
+
export function getProjectStems(projectId) {
|
|
23
|
+
const rows = getDb()
|
|
24
|
+
.prepare('SELECT * FROM project_stems WHERE project_id = ? ORDER BY asset_id, stem_type')
|
|
25
|
+
.all(projectId);
|
|
26
|
+
return rows.map(rowToStem);
|
|
27
|
+
}
|
|
28
|
+
/** Upsert a stem row (one per asset+stem_type — the unique index enforces it). */
|
|
29
|
+
export function upsertStem(params) {
|
|
30
|
+
const db = getDb();
|
|
31
|
+
const id = uuidv4();
|
|
32
|
+
db.prepare(`INSERT INTO project_stems (id, project_id, asset_id, stem_type, path, origin)
|
|
33
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
34
|
+
ON CONFLICT(asset_id, stem_type)
|
|
35
|
+
DO UPDATE SET path = excluded.path, origin = excluded.origin`).run(id, params.projectId, params.assetId, params.stemType, params.path, params.origin);
|
|
36
|
+
const row = db
|
|
37
|
+
.prepare('SELECT * FROM project_stems WHERE asset_id = ? AND stem_type = ?')
|
|
38
|
+
.get(params.assetId, params.stemType);
|
|
39
|
+
return rowToStem(row);
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=stems.js.map
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export interface Project {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
/** Folder name under the projects root. Human-readable slug for new projects;
|
|
5
|
+
* legacy projects keep their uuid folder. */
|
|
6
|
+
dirName: string;
|
|
7
|
+
createdAt: number;
|
|
8
|
+
updatedAt: number;
|
|
9
|
+
}
|
|
10
|
+
export type AssetKind = 'generation' | 'cover' | 'import' | 'reference' | 'master';
|
|
11
|
+
export interface ProjectAsset {
|
|
12
|
+
id: string;
|
|
13
|
+
projectId: string;
|
|
14
|
+
kind: AssetKind;
|
|
15
|
+
name: string;
|
|
16
|
+
/** Absolute path to the audio file on disk. */
|
|
17
|
+
path: string;
|
|
18
|
+
origin?: Record<string, unknown> | null;
|
|
19
|
+
sourceAssetId?: string | null;
|
|
20
|
+
refId?: string | null;
|
|
21
|
+
createdAt: number;
|
|
22
|
+
}
|
|
23
|
+
export declare const STEM_TYPES: readonly ["vocals", "kick", "snare", "toms", "hats", "bass", "ee"];
|
|
24
|
+
export type StemType = (typeof STEM_TYPES)[number];
|
|
25
|
+
export interface ProjectStem {
|
|
26
|
+
id: string;
|
|
27
|
+
projectId: string;
|
|
28
|
+
assetId: string;
|
|
29
|
+
stemType: StemType;
|
|
30
|
+
path: string;
|
|
31
|
+
origin: 'mvsep' | 'synthesized';
|
|
32
|
+
}
|
|
33
|
+
export interface ReferenceTrack {
|
|
34
|
+
id: string;
|
|
35
|
+
name: string;
|
|
36
|
+
audioPath: string;
|
|
37
|
+
cachedCurvePath: string | null;
|
|
38
|
+
curveStatus: 'none' | 'analyzing' | 'cached' | 'error';
|
|
39
|
+
createdAt: number;
|
|
40
|
+
}
|
|
41
|
+
export interface StackLane {
|
|
42
|
+
id: string;
|
|
43
|
+
sourceId?: string;
|
|
44
|
+
name: string;
|
|
45
|
+
/** Absolute audio path — the truth. */
|
|
46
|
+
path: string;
|
|
47
|
+
color?: string;
|
|
48
|
+
gainDb: number;
|
|
49
|
+
mute: boolean;
|
|
50
|
+
solo: boolean;
|
|
51
|
+
/** Clip start offset from timeline zero, in seconds. */
|
|
52
|
+
offsetSec: number;
|
|
53
|
+
}
|
|
54
|
+
export interface AppSettings {
|
|
55
|
+
projectsDirectory: string;
|
|
56
|
+
outputDirectory: string;
|
|
57
|
+
defaultGenModel: string;
|
|
58
|
+
defaultSmoothing: number;
|
|
59
|
+
defaultBitDepth: 16 | 24 | 32;
|
|
60
|
+
}
|
|
61
|
+
/** A single MVSEP job spec (see aurora docs/build-specs/mvsep-separation-contract.md). */
|
|
62
|
+
export interface MvsepJobSpec {
|
|
63
|
+
sep_type: string;
|
|
64
|
+
output_format: string;
|
|
65
|
+
is_demo: string;
|
|
66
|
+
add_opt1?: string;
|
|
67
|
+
add_opt2?: string;
|
|
68
|
+
}
|
|
69
|
+
export interface SeparationResultFile {
|
|
70
|
+
url: string;
|
|
71
|
+
filename: string;
|
|
72
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// Aurora domain types — mirrored from aurora/src/shared/types/index.ts (the
|
|
2
|
+
// locked contract). The MCP works against the SAME DB + project folders as the
|
|
3
|
+
// app, so these shapes must stay in lockstep with the app's schema v1.
|
|
4
|
+
export const STEM_TYPES = ['vocals', 'kick', 'snare', 'toms', 'hats', 'bass', 'ee'];
|
|
5
|
+
//# sourceMappingURL=types.js.map
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ericdisero/aurora-shared",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Shared operations layer for the Aurora MCP server and CLI: storage, Suno/MVSEP provider clients, background jobs, and the single tool surface both consume. Most users want @ericdisero/aurora-mcp-server or @ericdisero/aurora-cli instead.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./operations": "./dist/operations/index.js"
|
|
15
|
+
},
|
|
16
|
+
"files": ["dist", "!dist/**/*.map", "skills", "README.md"],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "node scripts/embed-skills.mjs && tsc",
|
|
19
|
+
"typecheck": "node scripts/embed-skills.mjs && tsc --noEmit",
|
|
20
|
+
"prepublishOnly": "npm run build"
|
|
21
|
+
},
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git+https://github.com/EricDisero/aurora-mcp.git",
|
|
25
|
+
"directory": "packages/shared"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"aurora",
|
|
29
|
+
"mcp",
|
|
30
|
+
"model-context-protocol",
|
|
31
|
+
"ai-music",
|
|
32
|
+
"music-generation",
|
|
33
|
+
"stem-separation",
|
|
34
|
+
"suno",
|
|
35
|
+
"mvsep",
|
|
36
|
+
"claude"
|
|
37
|
+
],
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=18"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@ffmpeg-installer/ffmpeg": "^1.1.0",
|
|
43
|
+
"better-sqlite3": "^11.6.0",
|
|
44
|
+
"uuid": "^11.0.0",
|
|
45
|
+
"zod": "^3.23.0"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/better-sqlite3": "^7.6.0",
|
|
49
|
+
"typescript": "^5.7.0"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: aurora-cost-discipline
|
|
3
|
+
description: Credit and spend discipline for every paid Aurora operation (Suno generation/cover/sounds/WAV, MVSEP splits). Fires before any aurora_generate, aurora_cover, aurora_sounds, aurora_split, or aurora_fetch_wav call.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Aurora Cost Discipline
|
|
7
|
+
|
|
8
|
+
Two metered providers sit behind Aurora's cloud ops. Spend is real money. The rules:
|
|
9
|
+
|
|
10
|
+
## Always
|
|
11
|
+
|
|
12
|
+
1. **`aurora_get_credits` BEFORE the first paid call of a session** — and after a batch, to log actual spend.
|
|
13
|
+
2. **Never re-split.** `aurora_split` burns real MVSEP credits; the op refuses when 7 stems already exist — don't work around it. Check `aurora_list_assets` first.
|
|
14
|
+
3. **Batch authorization, not per-call nagging.** When the user approves a multi-generation plan ("make me 4 braams and a riser"), that approval covers the enumerated batch — don't re-confirm each call. NEW spend beyond the approved batch needs a fresh ask.
|
|
15
|
+
|
|
16
|
+
## Known costs (sunoapi.org credits, measured 2026-06-10)
|
|
17
|
+
|
|
18
|
+
| Op | Cost |
|
|
19
|
+
|---|---|
|
|
20
|
+
| `aurora_sounds` | ~2.5 credits (~$0.0125) — the cheap verification + layer tool |
|
|
21
|
+
| `aurora_cover` | ~12 credits + ~0.4 per WAV fetch |
|
|
22
|
+
| `aurora_fetch_wav` | ~0.4 credits per conversion |
|
|
23
|
+
| `aurora_generate` | not yet measured — check credits before/after and report the delta |
|
|
24
|
+
| `aurora_split` | MVSEP credits, priced by audio duration (separate balance) |
|
|
25
|
+
| `aurora_get_credits`, all local ffmpeg/stack/project ops | FREE |
|
|
26
|
+
|
|
27
|
+
## Cheap-first ladder
|
|
28
|
+
|
|
29
|
+
- Verifying a pipeline or experimenting? `aurora_sounds` first (2.5 credits), full `aurora_generate` only when the user wants a track.
|
|
30
|
+
- Audition MP3s before paying for WAV upgrades; `aurora_fetch_wav` only the keepers.
|
|
31
|
+
- Local ops (`aurora_pitch_shift`, `aurora_convert`, stack everything) cost nothing — prefer them over regenerating.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: aurora-music-production
|
|
3
|
+
description: End-to-end Aurora workflow — create a project, generate or cover tracks, manufacture sounds, split into 7 stems, layer in the stack, export aligned WAVs for the DAW. Use when driving Aurora (the AI audio workbench) for any music production task.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Aurora Music Production Workflow
|
|
7
|
+
|
|
8
|
+
Aurora is the desktop layer between AI music generation and a real DAW: generate AI music, split anything into stems, keep it all organized. Files on disk ARE the product — everything you create lands in a real project folder the user can open, play, and drag into their DAW.
|
|
9
|
+
|
|
10
|
+
## Session start
|
|
11
|
+
|
|
12
|
+
1. `aurora_get_workspace_state` — projects list, key status, folder locations. Once per session.
|
|
13
|
+
2. `aurora_get_credits` — Suno credits + MVSEP minutes. ALWAYS before paid calls (see aurora-cost-discipline).
|
|
14
|
+
|
|
15
|
+
## The verbs
|
|
16
|
+
|
|
17
|
+
- **Generate** (`aurora_generate`) — full track from a prompt. 2 variations land as assets. 1-3 min.
|
|
18
|
+
- **Cover** (`aurora_cover`) — style-transform an existing asset or file: same musical content, new style. `audioWeight` is the dial: 0 = new style dominates, 1 = stay close to the source.
|
|
19
|
+
- **Sounds** (`aurora_sounds`) — samples, one-shots, loops with key/tempo lock. Fast (~20-30s), cheap (~2.5 credits). The layer-manufacturing tool: braams, booms, transitions, textures.
|
|
20
|
+
- **Split** (`aurora_split`) — ANY asset → 7 stems (vocals, kick, snare, toms, hats, bass, everything-else). REAL MVSEP credits; never re-split (the op refuses if 7 stems exist).
|
|
21
|
+
- **Stack** (`aurora_stack_*`) — layer assets/stems on lanes with offsets and gain, then `aurora_stack_export` for a sample-aligned multi-WAV bundle (drop at time zero in any DAW).
|
|
22
|
+
|
|
23
|
+
## Long-op discipline
|
|
24
|
+
|
|
25
|
+
Generation and splits take minutes. Prefer `background: true` + `aurora_get_job_status` polling every 10-20s:
|
|
26
|
+
|
|
27
|
+
- Status responses include `streamUrls` while a generation is still cooking — give the user the link, they can LISTEN ~30-45s in, minutes before files land.
|
|
28
|
+
- Split stems land PROGRESSIVELY: vocals/kick/snare/toms/hats/bass appear as each MVSEP job finishes; everything-else (ee) lands last.
|
|
29
|
+
- Jobs survive restarts — `aurora_list_jobs` recovers anything in flight.
|
|
30
|
+
|
|
31
|
+
## Files + organization
|
|
32
|
+
|
|
33
|
+
- Project folder: `generations/ covers/ imports/ references/ stems/<asset>/ masters/ stack-export/ stack.json`.
|
|
34
|
+
- MP3 lands first; `aurora_fetch_wav` upgrades a generation/cover to provider WAV (~0.4 credits).
|
|
35
|
+
- `aurora_pitch_shift` and `aurora_convert` are FREE local ffmpeg ops.
|
|
36
|
+
- Mastering (analyze → mix → export) lives in the Aurora app window — point the user there once stems exist; it is not agent-drivable yet.
|
|
37
|
+
|
|
38
|
+
## Suno prompting quick rules
|
|
39
|
+
|
|
40
|
+
- Custom mode = set `style` AND `title` together; then `prompt` carries the LYRICS.
|
|
41
|
+
- Non-custom mode: `prompt` is a track description.
|
|
42
|
+
- `negativeTags` is ONE comma-separated string ("Heavy Metal, Upbeat Drums").
|
|
43
|
+
- Sounds prompts: concrete and physical ("huge cinematic braam, dark low brass, trailer hit"), max 500 chars, lock `soundKey`/`tempo` when the track they'll sit in is known.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: aurora-split-and-stems
|
|
3
|
+
description: How Aurora's 7-stem split works (3 MVSEP jobs + phase cancellation), what the stems are, progressive landing, cost rules, and where stems live on disk. Use when calling aurora_split or working with split stems.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Aurora Split & Stems
|
|
7
|
+
|
|
8
|
+
## The 7 stems
|
|
9
|
+
|
|
10
|
+
`vocals, kick, snare, toms, hats, bass, ee` (everything-else). Only 5 come from MVSEP; **hats** and **ee** are synthesized locally by phase cancellation (hats = drums − kick − snare − toms; ee = original − vocals − drums − bass). This is why ee always lands LAST.
|
|
11
|
+
|
|
12
|
+
## How a split runs
|
|
13
|
+
|
|
14
|
+
3 parallel MVSEP jobs (vocals model, drum separation, bass model) on one standardized 44.1kHz float32 WAV. Stems land **progressively** as each job finishes:
|
|
15
|
+
|
|
16
|
+
- vocals job → `vocals`
|
|
17
|
+
- drums job → `kick`, `snare`, `toms`, `hats`
|
|
18
|
+
- bass job → `bass`
|
|
19
|
+
- all three done → `ee`
|
|
20
|
+
|
|
21
|
+
With `background: true`, `aurora_get_job_status` shows the per-job landing state — the user can start auditioning early stems while the rest cook. Typical total: 3-5 minutes (longer if the MVSEP queue is busy — free-tier keys run 1 concurrent job, so the 3 jobs may serialize).
|
|
22
|
+
|
|
23
|
+
## Cost rules
|
|
24
|
+
|
|
25
|
+
- REAL MVSEP credits, priced by audio duration. Check `aurora_get_credits` (mvsepPremiumMinutes) first.
|
|
26
|
+
- **Never re-split**: the op returns existing stems instead of spending again when a full set exists.
|
|
27
|
+
- Any asset kind splits: generations, covers, imports, AND references (split-a-reference is a first-class loop for studying an arrangement).
|
|
28
|
+
|
|
29
|
+
## On disk
|
|
30
|
+
|
|
31
|
+
Stems live at `<project>/stems/<asset-slug>-<id6>/*.wav` — 32-bit float, sample-aligned by construction. They are DAW-ready files: stack them (`aurora_stack_add_lane` with `stemType`), pitch them (`aurora_pitch_shift`), rip MIDI from them (`aurora_rip_midi`), or point the user at the folder.
|
|
32
|
+
|
|
33
|
+
Mastering against a reference (analyze → mix → export) happens in the Aurora app window from any split set — not agent-drivable yet.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: aurora-suno-prompting
|
|
3
|
+
description: Prompting guide for Aurora's Suno-backed generation ops — generate (full tracks), cover (style transforms, the audioWeight dial), and sounds (samples/one-shots/loops with key+tempo lock). Use when writing prompts for aurora_generate, aurora_cover, or aurora_sounds.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Suno Prompting for Aurora
|
|
7
|
+
|
|
8
|
+
## aurora_generate — full tracks
|
|
9
|
+
|
|
10
|
+
Two modes, switched by whether you set `style`/`title`:
|
|
11
|
+
|
|
12
|
+
- **Description mode** (no style/title): `prompt` describes the track — genre, mood, instrumentation, tempo feel, structure. One coherent paragraph beats keyword soup.
|
|
13
|
+
- **Custom mode** (`style` AND `title` set): `prompt` carries the LYRICS; `style` carries the genre/production language. The provider requires BOTH style and title together.
|
|
14
|
+
|
|
15
|
+
Controls: `instrumental: true` for no vocals; `vocalGender` male/female; `negativeTags` as ONE comma-separated string of styles to avoid ("Heavy Metal, Upbeat Drums").
|
|
16
|
+
|
|
17
|
+
## aurora_cover — style transforms
|
|
18
|
+
|
|
19
|
+
The source's musical content (melody, structure) is kept; the style is replaced.
|
|
20
|
+
|
|
21
|
+
- `audioWeight` is the single most important dial: **0 = the new style dominates, 1 = stay close to the source.** 0.5-0.7 is the useful middle for "same song, new genre".
|
|
22
|
+
- Custom mode rules are the same: `style` + `title` together, prompt describes the transformation target.
|
|
23
|
+
- Source cap: 8 minutes. Project asset (`sourceAssetId`) or external file (`sourcePath`).
|
|
24
|
+
|
|
25
|
+
## aurora_sounds — samples, one-shots, loops
|
|
26
|
+
|
|
27
|
+
The layer-manufacturing tool. Prompts are short (max 500 chars), physical, and concrete:
|
|
28
|
+
|
|
29
|
+
- Name the sound type: braam, boom, riser, downer, whoosh, impact, drone, texture, loop.
|
|
30
|
+
- Describe the material: "dark low brass", "metallic scrape", "sub-heavy 808", "airy granular pad".
|
|
31
|
+
- Context helps: "trailer hit", "transition", "intro swell".
|
|
32
|
+
- Lock `soundKey` (e.g. "Cm", "F#") and `tempo` (BPM) when the destination track is known — this is the point of the tool.
|
|
33
|
+
- `loop: true` for loopable textures/grooves.
|
|
34
|
+
|
|
35
|
+
Each call returns 2 variations — audition both before generating more.
|