Spaces:
Paused
Paused
Update app.py
Browse files
app.py
CHANGED
|
@@ -302,16 +302,33 @@ def midi_to_mp3(midi_obj: MidiFile, instrument: str = "Trumpet") -> Tuple[str, f
|
|
| 302 |
def get_fallback_exercise(instrument: str, level: str, key: str,
|
| 303 |
time_sig: str, measures: int) -> str:
|
| 304 |
key_notes = {
|
| 305 |
-
"C Major": ["C4", "D4", "E4", "G4"],
|
| 306 |
-
"G Major": ["
|
| 307 |
-
"D Major": ["D4", "E4", "F#4", "A4"],
|
| 308 |
-
"F Major": ["
|
| 309 |
-
"Bb Major": ["Bb3", "C4", "D4", "F4"],
|
| 310 |
-
"A Minor": ["A3", "B3", "C4", "D4", "E4", "G4"],
|
| 311 |
-
"E Minor": ["E3", "F#3", "G3", "A3", "B3", "D4"],
|
| 312 |
}
|
| 313 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 314 |
notes = key_notes.get(key, key_notes["C Major"])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 315 |
numerator, denominator = map(int, time_sig.split('/'))
|
| 316 |
|
| 317 |
# Calculate units based on 8th notes
|
|
@@ -329,14 +346,30 @@ def get_fallback_exercise(instrument: str, level: str, key: str,
|
|
| 329 |
cumulative = 0
|
| 330 |
current_units = 0
|
| 331 |
|
| 332 |
-
|
| 333 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 334 |
dur = random.choice(rhythm)
|
| 335 |
|
| 336 |
-
# Don't exceed
|
| 337 |
-
if current_units + dur >
|
| 338 |
-
dur =
|
| 339 |
-
if dur =
|
| 340 |
break
|
| 341 |
|
| 342 |
cumulative += dur
|
|
@@ -347,6 +380,16 @@ def get_fallback_exercise(instrument: str, level: str, key: str,
|
|
| 347 |
"cumulative_duration": cumulative
|
| 348 |
})
|
| 349 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 350 |
return json.dumps(result)
|
| 351 |
|
| 352 |
def get_style_based_on_level(level: str) -> str:
|
|
@@ -399,9 +442,19 @@ def query_mistral(prompt: str, instrument: str, level: str, key: str,
|
|
| 399 |
else:
|
| 400 |
style = get_style_based_on_level(level)
|
| 401 |
technique = get_technique_based_on_level(level)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 402 |
user_prompt = (
|
| 403 |
f"Create a {style} {instrument.lower()} exercise in {key} with {time_sig} time signature "
|
| 404 |
-
f"{technique} for a {level.lower()} player. {duration_constraint} "
|
| 405 |
"Output ONLY a JSON array of objects with the following structure: "
|
| 406 |
"[{{'note': string, 'duration': integer, 'cumulative_duration': integer}}] "
|
| 407 |
"Use standard note names (e.g., \"Bb4\", \"F#5\"). Monophonic only. "
|
|
|
|
| 302 |
def get_fallback_exercise(instrument: str, level: str, key: str,
|
| 303 |
time_sig: str, measures: int) -> str:
|
| 304 |
key_notes = {
|
| 305 |
+
"C Major": ["C4", "D4", "E4", "F4", "G4", "A4", "B4"],
|
| 306 |
+
"G Major": ["G3", "A3", "B3", "C4", "D4", "E4", "F#4"],
|
| 307 |
+
"D Major": ["D4", "E4", "F#4", "G4", "A4", "B4", "C#5"],
|
| 308 |
+
"F Major": ["F3", "G3", "A3", "Bb3", "C4", "D4", "E4"],
|
| 309 |
+
"Bb Major": ["Bb3", "C4", "D4", "Eb4", "F4", "G4", "A4"],
|
| 310 |
+
"A Minor": ["A3", "B3", "C4", "D4", "E4", "F4", "G4"],
|
| 311 |
+
"E Minor": ["E3", "F#3", "G3", "A3", "B3", "C4", "D4"],
|
| 312 |
}
|
| 313 |
|
| 314 |
+
# Get fundamental note from key signature
|
| 315 |
+
fundamental_note = key.split()[0] # Gets 'C' from 'C Major' or 'A' from 'A Minor'
|
| 316 |
+
is_major = "Major" in key
|
| 317 |
+
|
| 318 |
+
# Get notes for the key
|
| 319 |
notes = key_notes.get(key, key_notes["C Major"])
|
| 320 |
+
|
| 321 |
+
# Find fundamental note with octave for ending
|
| 322 |
+
fundamental_with_octave = None
|
| 323 |
+
for note in notes:
|
| 324 |
+
if note.startswith(fundamental_note):
|
| 325 |
+
fundamental_with_octave = note
|
| 326 |
+
break
|
| 327 |
+
|
| 328 |
+
# If not found, use the first note (should not happen with our key definitions)
|
| 329 |
+
if not fundamental_with_octave:
|
| 330 |
+
fundamental_with_octave = notes[0]
|
| 331 |
+
|
| 332 |
numerator, denominator = map(int, time_sig.split('/'))
|
| 333 |
|
| 334 |
# Calculate units based on 8th notes
|
|
|
|
| 346 |
cumulative = 0
|
| 347 |
current_units = 0
|
| 348 |
|
| 349 |
+
# Reserve at least 2 units for the final note
|
| 350 |
+
final_note_duration = min(4, max(2, rhythm[0])) # Between 2 and 4 units
|
| 351 |
+
available_units = target_units - final_note_duration
|
| 352 |
+
|
| 353 |
+
# Generate notes until we reach the available units
|
| 354 |
+
while current_units < available_units:
|
| 355 |
+
# Avoid minor 7th in major keys
|
| 356 |
+
if is_major:
|
| 357 |
+
# Filter out minor 7th notes (e.g., Bb in C major)
|
| 358 |
+
available_notes = [n for n in notes if not (n.startswith("Bb") and key == "C Major") and
|
| 359 |
+
not (n.startswith("F") and key == "G Major") and
|
| 360 |
+
not (n.startswith("C") and key == "D Major") and
|
| 361 |
+
not (n.startswith("Eb") and key == "F Major") and
|
| 362 |
+
not (n.startswith("Ab") and key == "Bb Major")]
|
| 363 |
+
else:
|
| 364 |
+
available_notes = notes
|
| 365 |
+
|
| 366 |
+
note = random.choice(available_notes)
|
| 367 |
dur = random.choice(rhythm)
|
| 368 |
|
| 369 |
+
# Don't exceed available units
|
| 370 |
+
if current_units + dur > available_units:
|
| 371 |
+
dur = available_units - current_units
|
| 372 |
+
if dur <= 0:
|
| 373 |
break
|
| 374 |
|
| 375 |
cumulative += dur
|
|
|
|
| 380 |
"cumulative_duration": cumulative
|
| 381 |
})
|
| 382 |
|
| 383 |
+
# Add the final note (fundamental of the key)
|
| 384 |
+
final_duration = target_units - current_units
|
| 385 |
+
if final_duration > 0:
|
| 386 |
+
cumulative += final_duration
|
| 387 |
+
result.append({
|
| 388 |
+
"note": fundamental_with_octave,
|
| 389 |
+
"duration": final_duration,
|
| 390 |
+
"cumulative_duration": cumulative
|
| 391 |
+
})
|
| 392 |
+
|
| 393 |
return json.dumps(result)
|
| 394 |
|
| 395 |
def get_style_based_on_level(level: str) -> str:
|
|
|
|
| 442 |
else:
|
| 443 |
style = get_style_based_on_level(level)
|
| 444 |
technique = get_technique_based_on_level(level)
|
| 445 |
+
# Extract fundamental note from key signature
|
| 446 |
+
fundamental_note = key.split()[0] # Gets 'C' from 'C Major' or 'A' from 'A Minor'
|
| 447 |
+
is_major = "Major" in key
|
| 448 |
+
|
| 449 |
+
# Create additional musical constraints
|
| 450 |
+
key_constraints = (
|
| 451 |
+
f"The exercise MUST end on the fundamental note of the key ({fundamental_note}). "
|
| 452 |
+
f"{'' if not is_major else 'For this major key, avoid using the minor 7th degree.'}"
|
| 453 |
+
)
|
| 454 |
+
|
| 455 |
user_prompt = (
|
| 456 |
f"Create a {style} {instrument.lower()} exercise in {key} with {time_sig} time signature "
|
| 457 |
+
f"{technique} for a {level.lower()} player. {duration_constraint} {key_constraints} "
|
| 458 |
"Output ONLY a JSON array of objects with the following structure: "
|
| 459 |
"[{{'note': string, 'duration': integer, 'cumulative_duration': integer}}] "
|
| 460 |
"Use standard note names (e.g., \"Bb4\", \"F#5\"). Monophonic only. "
|