;; phasevocoder test

;; load pianosyn only once
if ! fboundp(quote(piano-note)) then load "pianosyn"

variable *in*, *map*, *stretch*, *pitch*

;; test 1 - 1s sine tone stretched about 4x
function test1()
  begin
    set *in* = osc(c5) * pwl(0.1, 1, 0.9, 1, 1)
    set *map* = pwlv(0.05, 4.4, 1.1)
    play phasevocoder(*in*, *map*)
  end

;; test 2 - whole tone piano scale stretch about 8x
function test2()
  begin
    set *in* = seqrep(i, 7, piano-note(0.5, c4 + 2 * i, 100))
    set *map* = pwlv(1024.0 / 44100.0, 3.5 * 8, 3.5)
    play phasevocoder(*in*, *map*)
  end

;; test 3 - whole tone piano scale streched about 0.5x
function test3()
  begin
    set *in* = seqrep(i, 7, piano-note(0.5, c4 + 2 * i, 100))
    set *map* = pwlv(1024.0 / 44100.0, 3.5 * 0.5, 3.5)
    play phasevocoder(*in*, *map*)
  end

;; test 4 -- variable speed whole tone scale
function test4()
  begin with speed
    set *in* = seqrep(i, 30, piano-note(0.5, c2 + 2 * i, 100))
    set speed = ((lfo(0.1) * 4) ~ 5) + 0.1
    set *map* = (1024.0 / 44100.0) + integrate(speed)
    ; note: *map*'s maximum is about 13.3, so we will not hear
    ;   all of *in*
    play phasevocoder(*in*, *map*)
  end

;; test 5 -- start exactly at zero
function test5()
  begin
    set *in* = seqrep(i, 2, piano-note(1.0, c4 + 2 * i, 100))
    set *map* = pwlv(0, 3, 3)
    play phasevocoder(*in*, *map*)
  end


;; test6 -- time and pitch change, time stretch only
function test6()
  begin
    set *in* = seqrep(i, 5, piano-note(0.5, c4, 100)) ; 2.5s duration
    play pv-time-pitch(*in*, const(2, 3), seq(const(1), const(1.1), const(1.2), const(0.8), const(0.9)) ~ 0.501, 3, 4096)
  end


;; test7 -- fftsize
function test7()
  begin
    ; set *in* = hzosc(step-to-hz(pwlv(c5, 1, d5))) * pwl(0.1, 1, 0.9, 1, 1)
    ;; 44100 / 512
    set *in* = hzosc(44100.0 / 64.0) ; 64 sample period, bin 8, 689Hz 
    ; slope is 1.1 
    set *map* = pwlv(0.05, 1.1, 1.05)
    play phasevocoder(*in*, *map*, 512)
  end

;; test8 -- sweeping input
function test8()
  begin
    ; set *in* = hzosc(step-to-hz(pwlv(c5, 1, d5))) * pwl(0.1, 1, 0.9, 1, 1)
    ;; 44100 / 512
    set *in* = hzosc(600 + ramp(1) * 50) 
    ; slope is 1.1 
    set *map* = pwlv(0.05, 5, 1.05)
    play phasevocoder(*in*, *map*, 512)
  end

;; test 9 -- happy birthday to twinkle twinkle
function test9()
  begin
    with h1 = 0.000000,
         p1 = 0.166198, 
         b1 = 0.369078,
         d1 = 1.085618,
         t1 = 1.733822,
         y1 = 2.209605,
         h2 = 3.578676,
         p2 = 3.857731,
         b2 = 4.055933,
         d2 = 4.776379,
         t2 = 5.425378,
         y2 = 5.905255,
         h3 = 7.271426,
         p3 = 7.550667,
         b3 = 7.746811,
         d3 = 8.494934,
         u1 = 0.5 / (p1 - h1),
         u2 = 0.5 / (b1 - p1),
         u3 = 0.5 / (d1 - b1),
         u4 = 0.5 / (t1 - d1),
         u5 = 0.5 / (y1 - t1),
         u6 = 0.5 / (h2 - y1),
         u7 = 1.0 / (p2 - h2),
         u8 = 0.5 / (b2 - p2),
         u9 = 0.5 / (d2 - b2),
         u10 = 0.5 / (t2 - d2),
         u11 = 0.5 / (y2 - t2),
         u12 = 0.5 / (h3 - y2),
         u13 = 0.5 / (p3 - h3),
         u14 = 1.0 / (b3 - p3),
         v1 = to-ratio(60, 67),
         v2 = to-ratio(60, 67),
         v3 = to-ratio(67, 69),
         v4 = to-ratio(67, 67),
         v5 = to-ratio(69, 72),
         v6 = to-ratio(69, 71),
         v7 = to-ratio(67, 67),
         v8 = to-ratio(65, 67),
         v9 = to-ratio(65, 69),
         v10 = to-ratio(64, 67),
         v11 = to-ratio(64, 74),
         v12 = to-ratio(62, 72),
         v13 = to-ratio(62, 67),
         v14 = to-ratio(60, 67)
 
    set *in* = s-read("../audio/happy.wav")
    print ">>>>> original >>>>>"
    play *in* ;; hear the original
    set *stretch* = pwlv(    u1, p1, u1, p1, u2, b1, u2,
                         b1, u3, d1, u3, d1, u4, t1, u4,
                         t1, u5, y1, u5, y1, u6, h2, u6,
                         h2, u7, p2, u7, p2, u8, b2, u8,
                         b2, u9, d2, u9, d2, u10, t2, u10,
                         t2, u11, y2, u11, y2, u12, h3, u12,
                         h3, u13, p3, u13, p3, u14, b3, u14)
    set *pitch* = pwlv(    v1, p1, v1, p1, v2, b1, v2,
                       b1, v3, d1, v3, d1, v4, t1, v4,
                       t1, v5, y1, v5, y1, v6, h2, v6,
                       h2, v7, p2, v7, p2, v8, b2, v8,
                       b2, v9, d2, v9, d2, v10, t2, v10,
                       t2, v11, y2, v11, y2, v12, h3, v12,
                       h3, v13, p3, v13, p3, v14, b3, v14)
    print ">>>>> transformed >>>>>"
    play pv-time-pitch(*in*, *stretch*, *pitch*, 10)
  end

function to-ratio(a, b) return step-to-hz(a) / step-to-hz(b)

;; test 10 -- play 1 second of happy birthday stretched 8x
;;
function test10()
  begin
    with inp = s-read("../audio/happy.wav")
    play phasevocoder(inp, pwlv(0, 16, 4))
  end

function test11() ;; compare modes
  begin
    with inp = s-read("../audio/pv.wav")
    print ">>>> mode 0 >>>>>"
    play phasevocoder(inp, pwlv(0, 8, 2), 2048, 512, 0)
    print ">>>> mode 1 >>>>>"
    play phasevocoder(inp, pwlv(0, 8, 2), 2048, 512, 1)
    print ">>>> mode 2 >>>>>"
    play phasevocoder(inp, pwlv(0, 8, 2), 2048, 512, 2)
  end

function test-all()
  loop ;; construct test names as "TEST"+N and run them
    for i from 1 to 11   
    for fn = format(nil, "TEST~A", i)
    print "*****", fn, "*****"
    exec funcall(intern(fn))
  end

print "loaded phasevocoder.sal"

;exec test1()
;exec test2()
;exec test3()
;exec test4()
;exec test5()
;exec test6()
;exec test7()
;exec test8()
;exec test9()
;exec test10()
;exec test11()
exec test-all()

;; plot *spi, 10 ;; will crash Nyquist!
;; plot *in*, 10 ;; will crash Nyquist!

