"""Same idea, with an octave displacement; restrained bass support. Baseline is the accepted spanish-astra-01. Only bars 27–31 may change. """ from pathlib import Path import copy,json HERE=Path(__file__).resolve().parent s=json.loads((HERE/'base-score.json').read_text()) original=copy.deepcopy(s['events']) starts=s['soloBarStarts'] def at(bar,beat): b=bar-20 return starts[b]+beat*(starts[b+1]-starts[b])/4 # Keep every original lead note, its pitch class, rhythm and dynamic. # The existing Eb-C-A descending figure moves up one octave and continues # the same idea. No additional guitar notes or newly invented phrase. for e in s['events']: if e['part']=='guitar' and e['bar']==30 and e['beat'] in (1,1.5,2): e['pitch']+=12 e['string']=5 e['role']='original figure displaced one octave upward' # Preserve the first bass note, then replace the speculative fills with # sustained harmonic support. The next accepted bass/lead phrase is intact. s['events']=[e for e in s['events'] if not(e['part']=='bass' and 27<=e['bar']<=31)] s['events'].append(next(e for e in original if e['part']=='bass' and e['bar']==27 and e['beat']==0)) for bar,beat,pitch,hold,velocity in [ (27,2,36,1.70,.43), (28,0,41,3.45,.51), (29,0,40,3.40,.48), (30,0,39,3.40,.49), (31,0,36,3.35,.47), ]: s['events'].append(dict(part='bass',pitch=pitch,bar=bar,beat=beat, time=at(bar,beat),duration=at(bar,beat+hold)-at(bar,beat),velocity=velocity, string=0,role='restrained harmonic support; leave the lead room')) s['events'].sort(key=lambda e:e['time']) unchanged=lambda events:[e for e in events if not 27<=e['bar']<=31] assert unchanged(s['events'])==unchanged(original) g=[e for e in s['events'] if e['part']=='guitar'] o=[e for e in original if e['part']=='guitar'] assert len(g)==len(o) assert all(a['time']==b['time'] and a['duration']==b['duration'] and a['velocity']==b['velocity'] and a['pitch']%12==b['pitch']%12 for a,b in zip(g,o)) assert sum(a['pitch']!=b['pitch'] for a,b in zip(g,o))==3 s['description']='Our Spanish Love Song: Astra solo, an octave displacement with room from the bass.' s['arrangement']='Astra 1 is retained. Three existing guitar notes, Eb-C-A at 1:03.8–1:04.3, move up one octave; all lead pitch classes, onsets, durations and dynamics remain exact. Bass fills in bars 27–31 give way to sustained harmonic support. The approved theme, models, gains and phrase clock are unchanged. No samples or randomization.' s['revision']='Three guitar notes displaced one octave, with restrained bass in bars 27–31; baseline spanish-astra-01.' s['revisionWindow']={'firstBar':27,'lastBar':31,'start':at(27,0),'end':at(32,0),'baseline':'spanish-astra-01'} (HERE/'score.json').write_text(json.dumps(s,indent=2)+'\n') print('Three guitar pitches raised by 12 semitones; all lead rhythm/dynamics and pitch classes unchanged.')