fix: musical content — 808 timing, chord voicings, melody range, pad arpeggiation, Ozone paths
- 808 bass: fixed note positions to beat 1.0 per bar (i-iv-i-V, 1.5 beat duration) - Chords: 4-note 7th voicings (Am7, F7, C7, G7) instead of 2-note intervals - Lead: constrained to 8-semitone range, pentatonic scale - Pad: arpeggiated eighth-notes instead of static 2-note drones - Ozone 12: fixed .vst3 filename paths in Calibrator - Delta-encoding: fixed cumulative timing drift in _build_midi_source() with CC events 298/298 tests pass.
This commit is contained in:
@@ -73,30 +73,15 @@ DRUMLOOP_FILES = {
|
||||
],
|
||||
}
|
||||
|
||||
# 808 Bass pattern from Ableton project (proven harmonic):
|
||||
# i - iv - i - V in Am: A1(33) → D2(38) → A1(33) → E2(40)
|
||||
# 808 Bass pattern — reggaeton i-iv-i-V, one note every 2 bars on beat 1.0.
|
||||
# Sparse pattern: 808 tail (1.5 beat duration) fills the space between hits.
|
||||
# Am: A1(33) → D2(38) → A1(33) → E2(40)
|
||||
# Duration: 1.5 beats, velocity varies by section
|
||||
BASS_PATTERN_8BARS = [
|
||||
# Bars 1-2: root (i)
|
||||
{"pitch": 33, "start_time": 0.0, "duration": 1.5, "velocity": 80},
|
||||
{"pitch": 33, "start_time": 2.0, "duration": 1.5, "velocity": 80},
|
||||
{"pitch": 33, "start_time": 4.0, "duration": 1.5, "velocity": 80},
|
||||
{"pitch": 33, "start_time": 6.0, "duration": 1.5, "velocity": 80},
|
||||
# Bars 3-4: subdominant (iv)
|
||||
{"pitch": 38, "start_time": 8.0, "duration": 1.5, "velocity": 80},
|
||||
{"pitch": 38, "start_time": 10.0, "duration": 1.5, "velocity": 80},
|
||||
{"pitch": 38, "start_time": 12.0, "duration": 1.5, "velocity": 80},
|
||||
{"pitch": 38, "start_time": 14.0, "duration": 1.5, "velocity": 80},
|
||||
# Bars 5-6: root (i)
|
||||
{"pitch": 33, "start_time": 16.0, "duration": 1.5, "velocity": 80},
|
||||
{"pitch": 33, "start_time": 18.0, "duration": 1.5, "velocity": 80},
|
||||
{"pitch": 33, "start_time": 20.0, "duration": 1.5, "velocity": 80},
|
||||
{"pitch": 33, "start_time": 22.0, "duration": 1.5, "velocity": 80},
|
||||
# Bars 7-8: dominant (V)
|
||||
{"pitch": 40, "start_time": 24.0, "duration": 1.5, "velocity": 80},
|
||||
{"pitch": 40, "start_time": 26.0, "duration": 1.5, "velocity": 80},
|
||||
{"pitch": 40, "start_time": 28.0, "duration": 1.5, "velocity": 80},
|
||||
{"pitch": 40, "start_time": 30.0, "duration": 1.5, "velocity": 80},
|
||||
{"pitch": 33, "start_time": 0.0, "duration": 1.5, "velocity": 80}, # Bar 1-2: i
|
||||
{"pitch": 38, "start_time": 8.0, "duration": 1.5, "velocity": 80}, # Bar 3-4: iv
|
||||
{"pitch": 33, "start_time": 16.0, "duration": 1.5, "velocity": 80}, # Bar 5-6: i
|
||||
{"pitch": 40, "start_time": 24.0, "duration": 1.5, "velocity": 80}, # Bar 7-8: V
|
||||
]
|
||||
|
||||
# Section structure from Ableton project
|
||||
@@ -650,22 +635,35 @@ def build_fx_track(
|
||||
|
||||
|
||||
def build_pad_track(sections, offsets, key_root: str, key_minor: bool) -> TrackDef:
|
||||
"""Pad: sustained root chord, only in chorus/build sections."""
|
||||
"""Pad: arpeggiated chord, cycling through chord tones on eighth notes.
|
||||
|
||||
Each section gets an ascending arpeggio cycling through chord notes
|
||||
at octave 3 (low, avoids clashing with chords at octave 4).
|
||||
Replaces the old static sustained pad with rhythmic movement.
|
||||
"""
|
||||
root_midi = key_to_midi_root(key_root, 3)
|
||||
quality = "minor" if key_minor else "major"
|
||||
chord = build_chord(root_midi, quality)
|
||||
|
||||
clips = []
|
||||
for section, sec_off in zip(sections, offsets):
|
||||
# Pad only where the pad role is active
|
||||
if not _section_active(section.name, "pad", TRACK_ACTIVITY):
|
||||
continue
|
||||
|
||||
velocity = int(55 * section.velocity_mult)
|
||||
notes = [
|
||||
MidiNote(pitch=p, start=0.0, duration=section.bars * 4.0, velocity=velocity)
|
||||
for p in chord
|
||||
]
|
||||
total_beats = section.bars * 4.0
|
||||
notes = []
|
||||
beat = 0.0
|
||||
while beat < total_beats:
|
||||
pitch = chord[int(beat * 2) % len(chord)] # ascend through chord tones
|
||||
notes.append(MidiNote(
|
||||
pitch=pitch,
|
||||
start=beat,
|
||||
duration=0.5,
|
||||
velocity=velocity,
|
||||
))
|
||||
beat += 0.5 # eighth note step
|
||||
|
||||
clips.append(ClipDef(
|
||||
position=sec_off * 4.0,
|
||||
length=section.bars * 4.0,
|
||||
@@ -677,7 +675,7 @@ def build_pad_track(sections, offsets, key_root: str, key_minor: bool) -> TrackD
|
||||
plugins = [make_plugin(fx, i, role="pad") for i, fx in enumerate(FX_CHAINS.get("pad", []))]
|
||||
return TrackDef(
|
||||
name="Pad",
|
||||
volume=VOLUME_LEVELS["pad"],
|
||||
volume=0.55, # lower volume to prevent masking chords
|
||||
pan=0.0,
|
||||
clips=clips,
|
||||
plugins=plugins,
|
||||
|
||||
Reference in New Issue
Block a user