#!/usr/bin/env python3
"""Generate Chapter 3 figures and synthetic teaching-surrogate audio."""
from pathlib import Path
import wave
import numpy as np
import matplotlib.pyplot as plt

ROOT = Path(__file__).resolve().parents[3]
FIG = ROOT / "assets/figures/svg"
AUDIO = ROOT / "assets/audio/ch03"
FIG.mkdir(parents=True, exist_ok=True)
AUDIO.mkdir(parents=True, exist_ok=True)
FS = 48_000


def save(name):
    plt.tight_layout(); plt.savefig(FIG / name, format="svg", metadata={"Date": None}); plt.close()


def synthetic_strike(seconds=.25):
    t=np.arange(round(seconds*FS))/FS
    # Project-authored deterministic surrogate, not a historical or field recording.
    x=(np.sin(2*np.pi*317*t)+.55*np.sin(2*np.pi*701*t)+.25*np.sin(2*np.pi*1193*t))*np.exp(-18*t)
    x*=np.minimum(1,t/.002)
    return .65*x/np.max(np.abs(x))

x=synthetic_strike(); t=np.arange(len(x))/FS*1000
fig,ax=plt.subplots(figsize=(9,4)); ax.plot(t,x,color="#7f1d1d"); ax.set(xlabel="Time (ms)",ylabel="Amplitude",title="Synthetic strike teaching surrogate: one fixed trace"); ax.grid(alpha=.25); save("ch03-loop-to-object.svg")

fig,axes=plt.subplots(3,1,figsize=(9,7))
for ax,r in zip(axes,[.5,1,2]):
    idx=np.minimum((np.arange(max(1,int(len(x)/r)))*r).astype(int),len(x)-1)
    y=x[idx]; ax.plot(np.arange(len(y))/FS*1000,y,color="#0f6f70"); ax.set_title(f"rate r={r:g}: duration {len(y)/FS*1000:.0f} ms, pitch ratio {r:g}"); ax.set_ylabel("Amplitude")
axes[-1].set_xlabel("Time (ms)"); save("ch03-rate-triptych.svg")

env=np.exp(-8*np.arange(FS//2)/FS); rev=env[::-1]
fig,ax=plt.subplots(figsize=(9,4)); ax.plot(env,label="decay",color="#7f1d1d"); ax.plot(rev,label="reversed",color="#0f6f70"); ax.set(xlabel="Sample",ylabel="Amplitude",title="Reversal turns decay into approach"); ax.legend(); ax.grid(alpha=.25); save("ch03-reverse-envelope.svg")

events=[(0,24000,220),(24000,12000,330),(36000,24000,247),(60000,12000,440),(72000,36000,294)]
fig,ax=plt.subplots(figsize=(9,4));
for i,(start,duration,f) in enumerate(events): ax.broken_barh([(start/FS,duration/FS)],(i-.35,.7),facecolors="#0f6f70"); ax.text((start+duration/2)/FS,i,str(f)+" Hz",ha="center",va="center",color="white",fontsize=8)
ax.set(xlabel="Time (s)",ylabel="Event lane",yticks=range(5),title="Stored event controls: integer sample starts and durations"); save("ch03-paper-roll.svg")

# Concatenated audible comparison: single, four repeats, reverse, half and double rate.
clips=[x,np.tile(x,4),x[::-1]]
for r in [.5,2]:
    pos=np.arange(max(1,int(len(x)/r)))*r; left=np.floor(pos).astype(int); right=np.minimum(left+1,len(x)-1); frac=pos-left; clips.append(x[left]*(1-frac)+x[right]*frac)
silence=np.zeros(round(.25*FS)); out=np.concatenate([v for pair in zip(clips,[silence]*len(clips)) for v in pair])
with wave.open(str(AUDIO/"ch03-studio-transformations.wav"),"wb") as w:
    w.setparams((1,2,FS,len(out),"NONE","not compressed")); w.writeframes((np.clip(out,-1,1)*32767).astype("<i2").tobytes())
print("Generated Chapter 3 studio figures and synthetic-surrogate audio.")
