import librosa, numpy as np, json, sys from PIL import Image names=['takumi','phosphor','beckon','circle','warmth','dawn','picture','sun','copper','golden'] KEYS=['C','C#','D','D#','E','F','F#','G','G#','A','A#','B'] maj=np.array([6.35,2.23,3.48,2.33,4.38,4.09,2.52,5.19,2.39,3.66,2.29,2.88]); mnr=np.array([6.33,2.68,3.52,5.38,2.60,3.53,2.54,4.75,3.98,2.69,3.34,3.17]) out={} for n in names: y,sr=librosa.load(n+'.wav',sr=22050,mono=True) tempo,beats=librosa.beat.beat_track(y=y,sr=sr,units='time') ch=librosa.feature.chroma_cqt(y=y,sr=sr).mean(1) sc=[(np.corrcoef(np.roll(maj,k),ch)[0,1],KEYS[k]+' maj') for k in range(12)]+[(np.corrcoef(np.roll(mnr,k),ch)[0,1],KEYS[k]+' min') for k in range(12)] key=max(sc)[1] rms=librosa.feature.rms(y=y,hop_length=11025)[0] out[n]=dict(dur=len(y)/sr,tempo=float(np.atleast_1d(tempo)[0]),key=key,beats=[round(float(b),3) for b in beats],rms=[round(float(r),3) for r in rms]) S=librosa.amplitude_to_db(np.abs(librosa.stft(y,n_fft=2048,hop_length=512)),ref=np.max) M=librosa.feature.melspectrogram(y=y,sr=sr,n_mels=160,hop_length=512); M=librosa.power_to_db(M,ref=np.max) im=((np.clip(M,-70,0)+70)/70*255).astype(np.uint8)[::-1] Image.fromarray(im).resize((min(4000,im.shape[1]),320)).save(f'/tmp/claude-0/spec_{n}.png') print(f"{n:9s} {out[n]['dur']:6.1f}s {out[n]['tempo']:6.1f} bpm {key}") json.dump(out,open('/home/claude/afterlight/mosaic/analysis.json','w'))