salgadev commited on
Commit
2224fa6
·
verified ·
1 Parent(s): b2e4883

Sync from GitHub 44e6d8ff

Browse files
README.md CHANGED
@@ -1,3 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
1
  # Jam Buddy
2
 
3
  > An AI music companion that listens to what you play and joins in — at your
 
1
+ ---
2
+ title: Jam Buddy
3
+ emoji: 🎸
4
+ colorFrom: red
5
+ colorTo: purple
6
+ sdk: docker
7
+ app_port: 7860
8
+ pinned: false
9
+ short_description: You start playing, it joins in — an AI music companion.
10
+ ---
11
+
12
  # Jam Buddy
13
 
14
  > An AI music companion that listens to what you play and joins in — at your
apps/web/__tests__/prompt.test.ts CHANGED
@@ -54,13 +54,13 @@ describe("buildPrompt", () => {
54
  expect(negativePrompt).toContain("drums");
55
  });
56
 
57
- it("does not negate the buddy's own instrument family in the negative prompt (lead guitar + input guitar)", () => {
58
  const { negativePrompt } = buildPrompt({
59
  ...base,
60
- instrument: "lead",
61
  inputInstrument: "guitar",
62
  });
63
- // buddy=lead is in the guitar family; adding "guitar" to the negative
64
  // would steer SA3 away from the buddy itself, so we must NOT add it.
65
  expect(negativePrompt).not.toContain("guitar");
66
  });
 
54
  expect(negativePrompt).toContain("drums");
55
  });
56
 
57
+ it("does not negate the buddy's own instrument family in the negative prompt (guitar + input guitar)", () => {
58
  const { negativePrompt } = buildPrompt({
59
  ...base,
60
+ instrument: "guitar",
61
  inputInstrument: "guitar",
62
  });
63
+ // buddy=guitar is in the guitar family; adding "guitar" to the negative
64
  // would steer SA3 away from the buddy itself, so we must NOT add it.
65
  expect(negativePrompt).not.toContain("guitar");
66
  });
apps/web/app/page.tsx CHANGED
@@ -396,31 +396,19 @@ export default function HomePage() {
396
  </span>
397
  </header>
398
 
399
- {/* Instrument / trigger pads */}
400
- <section aria-labelledby="pads-label" className="mb-6">
401
- <h2
402
- id="pads-label"
403
- className="mb-2 font-mono text-[10px] uppercase tracking-widest text-[#7f829c]"
404
- >
405
- Instrument
406
- </h2>
407
- <div className="grid grid-cols-4 gap-2 sm:grid-cols-8">
408
- {INSTRUMENTS.map((inst) => (
409
- <Pad
410
- key={inst}
411
- label={INSTRUMENT_LABELS[inst]}
412
- selected={instrument === inst}
413
- onSelect={() => setInstrument(inst)}
414
- />
415
- ))}
416
- </div>
417
- </section>
418
-
419
- {/* Knob row */}
420
  <section
421
  aria-label="Style controls"
422
- className="mb-6 grid grid-cols-3 gap-4 rounded-xl bg-[#15161f] p-4"
423
  >
 
 
 
 
 
 
 
 
424
  <Knob
425
  label="Genre"
426
  value={GENRES.indexOf(genre)}
 
396
  </span>
397
  </header>
398
 
399
+ {/* Knob row all 4 knobs on one row */}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
400
  <section
401
  aria-label="Style controls"
402
+ className="mb-6 grid grid-cols-4 gap-4 rounded-xl bg-[#15161f] p-4"
403
  >
404
+ <Knob
405
+ label="Instrument"
406
+ value={INSTRUMENTS.indexOf(instrument)}
407
+ min={0}
408
+ max={INSTRUMENTS.length - 1}
409
+ onChange={(v) => setInstrument(INSTRUMENTS[v] ?? "guitar")}
410
+ format={(v) => INSTRUMENT_LABELS[INSTRUMENTS[v] ?? "guitar"] ?? ""}
411
+ />
412
  <Knob
413
  label="Genre"
414
  value={GENRES.indexOf(genre)}
apps/web/lib/jambuddy/prompt.ts CHANGED
@@ -19,14 +19,12 @@
19
  */
20
 
21
  export type BuddyInstrument =
 
22
  | "bass"
23
- | "lead"
24
- | "rhythm"
25
- | "synth"
26
  | "drums"
27
- | "sax"
28
- | "cleanguitar"
29
- | "overdrivenguitar";
30
 
31
  /**
32
  * What the user IS playing on their take. SA3 has no MIR — it cannot read the
@@ -62,14 +60,12 @@ export type BuddyMood =
62
 
63
  /** Instrument → AudioSparx `Instruments:` tag fragment (the "knob" options). */
64
  export const INSTRUMENT_PROMPTS: Readonly<Record<BuddyInstrument, string>> = {
 
65
  bass: "Bass Guitar, a grooving bass line, tight and in the pocket",
66
- lead: "Lead Guitar, a soaring melodic lead guitar riff",
67
- rhythm: "Rhythm Guitar, tight palm-muted power chords",
68
- synth: "Synth, a warm atmospheric pad",
69
  drums: "Drums, a punchy drum groove, kick and snare locked in",
 
 
70
  sax: "Saxophone, a warm breathy saxophone line with a rich tone",
71
- cleanguitar: "Clean Guitar, bright chimey clean electric guitar arpeggios",
72
- overdrivenguitar: "Overdriven Guitar, a gritty overdriven guitar riff with crunch",
73
  };
74
 
75
  /** Genre → AudioSparx `Genre:` tag. Matches the model's training vocab. */
@@ -107,14 +103,12 @@ const BASE_NEGATIVES: readonly string[] = [
107
  * for musical phrases.
108
  */
109
  export const MODEL_FOR_INSTRUMENT: Readonly<Record<BuddyInstrument, string>> = {
 
110
  bass: "small-music",
111
- lead: "small-music",
112
- rhythm: "small-music",
113
- synth: "small-music",
114
  drums: "small-sfx",
 
 
115
  sax: "small-music",
116
- cleanguitar: "small-music",
117
- overdrivenguitar: "small-music",
118
  };
119
 
120
  export interface BuddyKnobs {
@@ -201,28 +195,24 @@ function buddyInstrumentFamilyMatches(
201
  inputNoun: string,
202
  ): boolean {
203
  const family: Readonly<Record<BuddyInstrument, string>> = {
 
204
  bass: "bass",
205
- lead: "guitar",
206
- rhythm: "guitar",
207
- synth: "synth",
208
  drums: "drums",
 
 
209
  sax: "sax",
210
- cleanguitar: "guitar",
211
- overdrivenguitar: "guitar",
212
  };
213
  return family[instrument] === inputNoun;
214
  }
215
 
216
  /** The knob options, for rendering dropdowns. */
217
  export const INSTRUMENTS: readonly BuddyInstrument[] = [
 
218
  "bass",
219
- "lead",
220
- "rhythm",
221
- "synth",
222
  "drums",
 
 
223
  "sax",
224
- "cleanguitar",
225
- "overdrivenguitar",
226
  ];
227
  /** Input-instrument vocab (what the user is playing on the take). */
228
  export const INPUT_INSTRUMENTS: readonly InputInstrument[] = [
@@ -281,7 +271,6 @@ export const MOOD_LABELS: Readonly<Record<BuddyMood, string>> = {
281
  };
282
  /** Human-friendly labels for the buddy-instrument pads. */
283
  export const INSTRUMENT_LABELS: Readonly<Record<BuddyInstrument, string>> = {
284
- bass: "Bass", lead: "Lead Guitar", rhythm: "Rhythm Guitar", synth: "Synth",
285
- drums: "Drums", sax: "Sax", cleanguitar: "Clean Guitar",
286
- overdrivenguitar: "Overdriven Guitar",
287
  };
 
19
  */
20
 
21
  export type BuddyInstrument =
22
+ | "guitar"
23
  | "bass"
 
 
 
24
  | "drums"
25
+ | "synth"
26
+ | "piano"
27
+ | "sax";
28
 
29
  /**
30
  * What the user IS playing on their take. SA3 has no MIR — it cannot read the
 
60
 
61
  /** Instrument → AudioSparx `Instruments:` tag fragment (the "knob" options). */
62
  export const INSTRUMENT_PROMPTS: Readonly<Record<BuddyInstrument, string>> = {
63
+ guitar: "Guitar, a tight electric guitar riff",
64
  bass: "Bass Guitar, a grooving bass line, tight and in the pocket",
 
 
 
65
  drums: "Drums, a punchy drum groove, kick and snare locked in",
66
+ synth: "Synth, a warm atmospheric pad",
67
+ piano: "Piano, a melodic piano part",
68
  sax: "Saxophone, a warm breathy saxophone line with a rich tone",
 
 
69
  };
70
 
71
  /** Genre → AudioSparx `Genre:` tag. Matches the model's training vocab. */
 
103
  * for musical phrases.
104
  */
105
  export const MODEL_FOR_INSTRUMENT: Readonly<Record<BuddyInstrument, string>> = {
106
+ guitar: "small-music",
107
  bass: "small-music",
 
 
 
108
  drums: "small-sfx",
109
+ synth: "small-music",
110
+ piano: "small-music",
111
  sax: "small-music",
 
 
112
  };
113
 
114
  export interface BuddyKnobs {
 
195
  inputNoun: string,
196
  ): boolean {
197
  const family: Readonly<Record<BuddyInstrument, string>> = {
198
+ guitar: "guitar",
199
  bass: "bass",
 
 
 
200
  drums: "drums",
201
+ synth: "synth",
202
+ piano: "piano",
203
  sax: "sax",
 
 
204
  };
205
  return family[instrument] === inputNoun;
206
  }
207
 
208
  /** The knob options, for rendering dropdowns. */
209
  export const INSTRUMENTS: readonly BuddyInstrument[] = [
210
+ "guitar",
211
  "bass",
 
 
 
212
  "drums",
213
+ "synth",
214
+ "piano",
215
  "sax",
 
 
216
  ];
217
  /** Input-instrument vocab (what the user is playing on the take). */
218
  export const INPUT_INSTRUMENTS: readonly InputInstrument[] = [
 
271
  };
272
  /** Human-friendly labels for the buddy-instrument pads. */
273
  export const INSTRUMENT_LABELS: Readonly<Record<BuddyInstrument, string>> = {
274
+ guitar: "Guitar", bass: "Bass", drums: "Drums", synth: "Synth",
275
+ piano: "Piano", sax: "Sax",
 
276
  };
tools/jam_buddy.py CHANGED
@@ -43,14 +43,12 @@ import torchaudio
43
 
44
  # Instrument -> AudioSparx `Instruments:` tag fragment (the "knob" options)
45
  INSTRUMENTS = {
 
46
  "bass": "Bass Guitar, a grooving bass line, tight and in the pocket",
47
- "lead": "Lead Guitar, a soaring melodic lead guitar riff",
48
- "rhythm": "Rhythm Guitar, tight palm-muted power chords",
49
- "synth": "Synth, a warm atmospheric pad",
50
  "drums": "Drums, a punchy drum groove, kick and snare locked in",
 
 
51
  "sax": "Saxophone, a warm breathy saxophone line with a rich tone",
52
- "cleanguitar": "Clean Guitar, bright chimey clean electric guitar arpeggios",
53
- "overdrivenguitar": "Overdriven Guitar, a gritty overdriven guitar riff with crunch",
54
  }
55
 
56
  # Genre tempo-range prior (BPM) to disambiguate the octave-drop on AUDIO.
 
43
 
44
  # Instrument -> AudioSparx `Instruments:` tag fragment (the "knob" options)
45
  INSTRUMENTS = {
46
+ "guitar": "Guitar, a tight electric guitar riff",
47
  "bass": "Bass Guitar, a grooving bass line, tight and in the pocket",
 
 
 
48
  "drums": "Drums, a punchy drum groove, kick and snare locked in",
49
+ "synth": "Synth, a warm atmospheric pad",
50
+ "piano": "Piano, a melodic piano part",
51
  "sax": "Saxophone, a warm breathy saxophone line with a rich tone",
 
 
52
  }
53
 
54
  # Genre tempo-range prior (BPM) to disambiguate the octave-drop on AUDIO.
tools/jam_buddy_api.py CHANGED
@@ -37,14 +37,12 @@ CREDITS_PER_GEN = 26
37
 
38
  # Instrument -> AudioSparx `Instruments:` tag fragment (matches jam_buddy.py)
39
  INSTRUMENTS = {
 
40
  "bass": "Bass Guitar, a grooving bass line, tight and in the pocket",
41
- "lead": "Lead Guitar, a soaring melodic lead guitar riff",
42
- "rhythm": "Rhythm Guitar, tight palm-muted power chords",
43
- "synth": "Synth, a warm atmospheric pad",
44
  "drums": "Drums, a punchy drum groove, kick and snare locked in",
 
 
45
  "sax": "Saxophone, a warm breathy saxophone line with a rich tone",
46
- "cleanguitar": "Clean Guitar, bright chimey clean electric guitar arpeggios",
47
- "overdrivenguitar": "Overdriven Guitar, a gritty overdriven guitar riff with crunch",
48
  }
49
  DEFAULT_GENRE = "any"
50
  GENRE_TEMPO = {
 
37
 
38
  # Instrument -> AudioSparx `Instruments:` tag fragment (matches jam_buddy.py)
39
  INSTRUMENTS = {
40
+ "guitar": "Guitar, a tight electric guitar riff",
41
  "bass": "Bass Guitar, a grooving bass line, tight and in the pocket",
 
 
 
42
  "drums": "Drums, a punchy drum groove, kick and snare locked in",
43
+ "synth": "Synth, a warm atmospheric pad",
44
+ "piano": "Piano, a melodic piano part",
45
  "sax": "Saxophone, a warm breathy saxophone line with a rich tone",
 
 
46
  }
47
  DEFAULT_GENRE = "any"
48
  GENRE_TEMPO = {