!******************************************************************************!
! This tests the functionality of convolve.
!
! @author  Scott Fernandez, Jason Broussard, Jeanette McCall
! @since   NeXtMidas 2.1.1
!******************************************************************************!
startmacro s:func[""]
  switch KEEP        keep     GET DEF=FALSE SDEF=TRUE  ! to keep generated / output files

  set  fnprefix "convolve_^{env.pid}"
  if func NEQS "" and func NEQS "ALL" then
    call test_^{func}
    stop
  endif

  call test_basic
  call test_advanced
  ! saf: switch /tl not yet implemented
  ! call test_xferLength
endmacro

!******************************************************************************!
! If an unexpected exception is caught, mark test as failed, unless it is expected
!******************************************************************************!
procedure processException m:emsg
  if expectedException REXISTS then
    assert/text="^reg.main.name: Expected ERROR starts with: ^{expectedException}" expectedException EQSS emsg.data.message
    remove expectedException
  else
    assert/text="^reg.main.name: Caught unexpected exception ^{emsg.data}" "FALSE" isTrue
    if "Trace" SUBS ENV.DEBUG then invoke ,, emsg.data.printStackTrace()
  endif
return

!******************************************************************************!
! Basic test
procedure test_basic
  ! test corrected and switched to SD (for fuller testing) in 3.9.5
  WAVEFORM,ram:sin1,SD,128k,SIN,1,.01,0,0,1
  ! Need to create delta function or 1 and then zeros but can not use SHAPE=PULSE
  ! to get pulse on first element because of the way the code is written
  WAVEFORM,ram:deltafunc,SD,1,constant,1,.01,0,0,1
  WAVEFORM OUT=ram:z9 FORM=SD elem=9 shape=zero freq=0.01 START=0 delta=1
  mergefile ram:z9 deltafunc
  convolve ram:sin1 ram:deltafunc ram:convolve_out
  fcalc ram:diff ram:sin1 ram:convolve_out -
  maxmin/quiet ram:diff max1 min1

  assert/text="^reg.main.name: Compare output with input (impulse Dirac Delta)" max1 eq 0 and min1 eq 0

  erase ram:sin1 ram:z9 ram:deltafunc ram:convolve_out ram:diff
return

!******************************************************************************!
! Advanced tests
procedure test_advanced
  set expected1 "nxm.dsp.test.test_convolve_expected1.prm"
  WAVEFORM OUT=ram:in    FORM=SF ELEM=25 SHAPE=CONSTANT AMP=0
  WAVEFORM OUT=ram:merge FORM=SF ELEM=15 SHAPE=CONSTANT AMP=10
  MERGEFILE IN=ram:in OUT=ram:merge
  convolve ram:merge ram:merge ram:out1
  COMPARE IN1=expected1 IN2=ram:out1 MAX_OUT=junk1 MIN_OUT=junk2  RESULT=same

  assert/text="^reg.main.name: Comparing output to known values (impulse is SF)" same eq 1

  set expected2 "nxm.dsp.test.test_convolve_expected2.prm"
  convolve ram:out1 ram:out1 ram:out2
  COMPARE IN1=expected2 IN2=ram:out2 MAX_OUT=junk1 MIN_OUT=junk2 RESULT=same
  assert/text="^reg.main.name: Comparing output to known values (impulse is SF)" same eq 1

  ! Addition types (more than SF) in 3.9.2 - note these are only added in 39x, as they use table2blue10002000
  nxm.sys.test.table2blue10002000 IN={FORMAT=SD,DATA=D:(1,-0.5,-0.4,-0.2)} OUT=ram:conv_impulse_response_d.tmp
  nxm.sys.test.table2blue10002000 IN={FORMAT=SD,DATA=D:(0,-1,-1.1,2,1.3,1.3,0.8,0,-0.8)} OUT=ram:conv_input_d.tmp
  nxm.sys.test.table2blue10002000 IN={FORMAT=SD,DATA=D:(0,-1.0,-0.6,2.95,0.94,0.07,-0.77,-1.18,-1.38,0.24,0.32,0.16)} OUT=ram:conv_expected_d.tmp
  convolve ram:conv_input_d.tmp ram:conv_impulse_response_d.tmp ram:conv_out_double.tmp
  assert/text="^reg.main.name: Comparing output to known values (impulse is SD)" ram:conv_out_double.tmp FEQ/D/T ram:conv_expected_d.tmp

  nxm.sys.test.table2blue10002000 IN={FORMAT=SX,DATA=(100,-50,-40,-20)} OUT=ram:conv_impulse_response_x.tmp
  nxm.sys.test.table2blue10002000 IN={FORMAT=SX,DATA=(0,-100,-110,200,130,130,80,0,-80)} OUT=ram:conv_input_x.tmp
  nxm.sys.test.table2blue10002000 IN={FORMAT=SX,DATA=(0,-10000,-6000,29500,9400,700,-7700,-11800,-13800,2400,3200,1600)} OUT=ram:conv_expected_x.tmp
  convolve ram:conv_input_x.tmp ram:conv_impulse_response_x.tmp ram:conv_out_xlong.tmp
  assert/text="^reg.main.name: Comparing output to known values (impulse is SX)" ram:conv_out_xlong.tmp FEQ/D/T ram:conv_expected_x.tmp

  nxm.sys.test.table2blue10002000 IN={FORMAT=SL,DATA=(100,-50,-40,-20)} OUT=ram:conv_impulse_response_l.tmp
  nxm.sys.test.table2blue10002000 IN={FORMAT=SL,DATA=(0,-100,-110,200,130,130,80,0,-80)} OUT=ram:conv_input_l.tmp
  nxm.sys.test.table2blue10002000 IN={FORMAT=SL,DATA=(0,-10000,-6000,29500,9400,700,-7700,-11800,-13800,2400,3200,1600)} OUT=ram:conv_expected_l.tmp
  convolve ram:conv_input_l.tmp ram:conv_impulse_response_l.tmp ram:conv_out_long.tmp
  assert/text="^reg.main.name: Comparing output to known values (impulse is SL)" ram:conv_out_long.tmp FEQ/D/T ram:conv_expected_l.tmp

  nxm.sys.test.table2blue10002000 IN={FORMAT=SI,DATA=(100,-50,-40,-20)} OUT=ram:conv_impulse_response_i.tmp
  nxm.sys.test.table2blue10002000 IN={FORMAT=SI,DATA=(0,-100,-110,200,130,130,80,0,-80)} OUT=ram:conv_input_i.tmp
  nxm.sys.test.table2blue10002000 IN={FORMAT=SI,DATA=(0,-10000,-6000,29500,9400,700,-7700,-11800,-13800,2400,3200,1600)} OUT=ram:conv_expected_i.tmp
  convolve ram:conv_input_i.tmp ram:conv_impulse_response_i.tmp ram:conv_out_int.tmp
  assert/text="^reg.main.name: Comparing output to known values (impulse is SI)" ram:conv_out_int.tmp FEQ/D/T ram:conv_expected_i.tmp

  erase ram:out1 ram:out2 ram:in ram:merge
  erase ram:conv_impulse_response_l.tmp ram:conv_impulse_response_d.tmp ram:conv_input_d.tmp ram:conv_input_l.tmp
  erase ram:conv_out_double.tmp ram:conv_expected_l.tmp
return

!******************************************************************************!
! Test transfer length.
procedure test_xferLength
  ! Randomize impulse and input sizes, make sure at least 1
  CALCULATOR/QUIET impLength RANDOM 401 * FLOOR 1 +
  CALCULATOR/QUIET inpLength RANDOM 2k * FLOOR 1 +
  WAVEFORM OUT=^{fnprefix}_imp FORM=SF ELEM=impLength SHAPE=CONSTANT AMP=10
  WAVEFORM OUT=^{fnprefix}_in  FORM=SF ELEM=inpLength SHAPE=SIN AMP=5

  ! Compare tl=inpLength and tl=impLength
  convolve ^{fnprefix}_in ^{fnprefix}_imp ^{fnprefix}_out1 /tl=impLength
  convolve ^{fnprefix}_in ^{fnprefix}_imp ^{fnprefix}_out2 /tl=inpLength
  COMPARE IN1=^{fnprefix}_out1 IN2=^{fnprefix}_out2 MAX_OUT=junk1 MIN_OUT=junk2 RESULT=same
  assert/text="^reg.main.name: Comparing output with transfer lengths at input sizes" same eq 1

  ! Compare probably tl < impLength

  ! 1 + floor( (impLength-1)*random ), less than or equal to impLength
  CALCULATOR/QUIET rand 1 impLength 1 - RANDOM * FLOOR +
  convolve ^{fnprefix}_in ^{fnprefix}_imp ^{fnprefix}_out2 /tl=rand
  COMPARE IN1=^{fnprefix}_out1 IN2=^{fnprefix}_out2 MAX_OUT=junk1 MIN_OUT=junk2 RESULT=same
  assert/text="^reg.main.name: Comparing to output with small transfer length" same eq 1
  
  ! Compare probably impLength < tl < inpLength
  
  ! floor( |inpLength-impLength|*random) ) + impLength, greater than or
  ! equal to impLength, probably less than inpLength, probably in between
  CALCULATOR/QUIET rand impLength inpLength impLength - ABS RANDOM * FLOOR +
  convolve ^{fnprefix}_in ^{fnprefix}_imp ^{fnprefix}_out2 /tl=rand
  COMPARE IN1=^{fnprefix}_out1 IN2=^{fnprefix}_out2 MAX_OUT=junk1 MIN_OUT=junk2 RESULT=same
  assert/text="^reg.main.name: Comparing to output with transfer length in between" same eq 1

  ! Compare tl = inpLength + ceil(1M*random) > inpLength
  CALCULATOR/QUIET rand inpLength 1M RANDOM * CEIL +
  convolve ^{fnprefix}_in ^{fnprefix}_imp ^{fnprefix}_out2 /tl=rand
  COMPARE/QUIET IN1=^{fnprefix}_out1 IN2=^{fnprefix}_out2 MAX_OUT=junk1 MIN_OUT=junk2 RESULT=same
  assert/text="^reg.main.name: Comparing to output with very large transfer length" same eq 1

  if keep isFalse then
    erase ^{fnprefix}_in ^{fnprefix}_imp ^{fnprefix}_out1 ^{fnprefix}_out2
  endif
return
