Spaces:
Running
Running
Commit ·
256d374
1
Parent(s): 78f88e1
refined control options.
Browse files- app.py +8 -8
- assets/styles.json +2 -2
- web/score-player.js +6 -0
app.py
CHANGED
|
@@ -50,8 +50,8 @@ OUTPUT_PREFIX = '✨ ' # ✨ session outputs
|
|
| 50 |
# vocabulary + values seen in examples.
|
| 51 |
_STYLES = json.load(open(os.path.join(ASSET_DIR, 'styles.json'), encoding='utf-8'))
|
| 52 |
COMPOSERS = _STYLES['composers']
|
|
|
|
| 53 |
GENRES = _STYLES['genres']
|
| 54 |
-
INSTRUMENTS = _STYLES['instruments']
|
| 55 |
|
| 56 |
_GEN = None
|
| 57 |
|
|
@@ -184,17 +184,17 @@ def load_library ():
|
|
| 184 |
_STYLE_LINE_RE = re.compile(r'^%(?!%).*$')
|
| 185 |
|
| 186 |
|
| 187 |
-
def sync_prompt (composer,
|
| 188 |
'''Rewrite the metadata-prompt text from the three style dropdowns.
|
| 189 |
|
| 190 |
The model is trained on the `--styles-in-comments` format: style is carried by
|
| 191 |
leading `%<value>` comment lines, ordered period/composer/instrumentation (matching
|
| 192 |
-
abc2lilylet's catalogCommentLines: %<
|
| 193 |
are regenerated from the dropdowns and placed at the top; any other line the user
|
| 194 |
typed (e.g. a `[staves "..."]` header) is preserved below in its original order.
|
| 195 |
'''
|
| 196 |
lines = []
|
| 197 |
-
for value in (
|
| 198 |
value = (value or '').strip()
|
| 199 |
if value:
|
| 200 |
lines.append(f'%{value}')
|
|
@@ -485,9 +485,9 @@ def build_ui ():
|
|
| 485 |
with gr.Row():
|
| 486 |
composer = gr.Dropdown(label='composer', choices=COMPOSERS, value='',
|
| 487 |
allow_custom_value=True)
|
| 488 |
-
|
| 489 |
allow_custom_value=True)
|
| 490 |
-
|
| 491 |
allow_custom_value=True)
|
| 492 |
prompt = gr.Textbox(label='Metadata prompt', lines=3, value='',
|
| 493 |
placeholder='extra metadata lines, e.g.\n[key "C major"]\n(optional)')
|
|
@@ -542,8 +542,8 @@ def build_ui ():
|
|
| 542 |
demo.load(None, None, None, js=_JS_HELPERS)
|
| 543 |
|
| 544 |
# style dropdowns -> keep the metadata-prompt text box in sync
|
| 545 |
-
for field in (composer,
|
| 546 |
-
field.change(sync_prompt, inputs=[composer,
|
| 547 |
|
| 548 |
# Generate: a single click dep that runs the gate js (SVG-only, player
|
| 549 |
# hidden) and then the streaming model fn — `js=` on a backend click runs
|
|
|
|
| 50 |
# vocabulary + values seen in examples.
|
| 51 |
_STYLES = json.load(open(os.path.join(ASSET_DIR, 'styles.json'), encoding='utf-8'))
|
| 52 |
COMPOSERS = _STYLES['composers']
|
| 53 |
+
PERIODS = _STYLES['periods']
|
| 54 |
GENRES = _STYLES['genres']
|
|
|
|
| 55 |
|
| 56 |
_GEN = None
|
| 57 |
|
|
|
|
| 184 |
_STYLE_LINE_RE = re.compile(r'^%(?!%).*$')
|
| 185 |
|
| 186 |
|
| 187 |
+
def sync_prompt (composer, period, genre, current):
|
| 188 |
'''Rewrite the metadata-prompt text from the three style dropdowns.
|
| 189 |
|
| 190 |
The model is trained on the `--styles-in-comments` format: style is carried by
|
| 191 |
leading `%<value>` comment lines, ordered period/composer/instrumentation (matching
|
| 192 |
+
abc2lilylet's catalogCommentLines: %<period> / %<composer> / %<genre>). These
|
| 193 |
are regenerated from the dropdowns and placed at the top; any other line the user
|
| 194 |
typed (e.g. a `[staves "..."]` header) is preserved below in its original order.
|
| 195 |
'''
|
| 196 |
lines = []
|
| 197 |
+
for value in (period, composer, genre):
|
| 198 |
value = (value or '').strip()
|
| 199 |
if value:
|
| 200 |
lines.append(f'%{value}')
|
|
|
|
| 485 |
with gr.Row():
|
| 486 |
composer = gr.Dropdown(label='composer', choices=COMPOSERS, value='',
|
| 487 |
allow_custom_value=True)
|
| 488 |
+
period = gr.Dropdown(label='period', choices=PERIODS, value='',
|
| 489 |
allow_custom_value=True)
|
| 490 |
+
genre = gr.Dropdown(label='genre', choices=GENRES, value='',
|
| 491 |
allow_custom_value=True)
|
| 492 |
prompt = gr.Textbox(label='Metadata prompt', lines=3, value='',
|
| 493 |
placeholder='extra metadata lines, e.g.\n[key "C major"]\n(optional)')
|
|
|
|
| 542 |
demo.load(None, None, None, js=_JS_HELPERS)
|
| 543 |
|
| 544 |
# style dropdowns -> keep the metadata-prompt text box in sync
|
| 545 |
+
for field in (composer, period, genre):
|
| 546 |
+
field.change(sync_prompt, inputs=[composer, period, genre, prompt], outputs=[prompt])
|
| 547 |
|
| 548 |
# Generate: a single click dep that runs the gate js (SVG-only, player
|
| 549 |
# hidden) and then the streaming model fn — `js=` on a backend click runs
|
assets/styles.json
CHANGED
|
@@ -18,6 +18,6 @@
|
|
| 18 |
"Ravel, Maurice",
|
| 19 |
"Shostakovich, Dmitry"
|
| 20 |
],
|
| 21 |
-
"
|
| 22 |
-
"
|
| 23 |
}
|
|
|
|
| 18 |
"Ravel, Maurice",
|
| 19 |
"Shostakovich, Dmitry"
|
| 20 |
],
|
| 21 |
+
"periods": ["Baroque", "Classical", "Romantic", "Modern"],
|
| 22 |
+
"genres": ["Keyboard", "Choral", "Chamber", "Orchestral"]
|
| 23 |
}
|
web/score-player.js
CHANGED
|
@@ -495,6 +495,12 @@
|
|
| 495 |
});
|
| 496 |
|
| 497 |
initVerovio(); // warm up early
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 498 |
}
|
| 499 |
|
| 500 |
// Public API consumed by app.py's injected glue.
|
|
|
|
| 495 |
});
|
| 496 |
|
| 497 |
initVerovio(); // warm up early
|
| 498 |
+
// Start loading the sound library (FluidSynth GM soundfont, ~40MB) right away
|
| 499 |
+
// at page mount rather than deferring to the first play — the AudioContext is
|
| 500 |
+
// created suspended (no autoplay-policy violation) and the fetch/worklet load
|
| 501 |
+
// proceed in the background, so the library is usually ready before the user
|
| 502 |
+
// hits play. initAudio() is idempotent; buildPlayer() later just reuses it.
|
| 503 |
+
initAudio();
|
| 504 |
}
|
| 505 |
|
| 506 |
// Public API consumed by app.py's injected glue.
|