;;     fv10k1.m4 - fv10k1 package
;;     This implements Jezar Wakefield's Freeverb algorithm
;;         
;;     Copyright (C) 2001 Oleg Smirnov <smirnov@astron.nl>
;;    
;;     This program is free software; you can redistribute it and/or modify
;;     it under the terms of the GNU General Public License as published by
;;     the Free Software Foundation; either version 2 of the License, or
;;     (at your option) any later version.
;; 
;;     This program is distributed in the hope that it will be useful,
;;     but WITHOUT ANY WARRANTY; without even the implied warranty of
;;     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;;     GNU General Public License for more details.
;; 
;;     You should have received a copy of the GNU General Public License
;;     along with this program; if not, write to the Free Software
;;     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
;; 
;; $Id: fv10k1.m4,v 1.1 2001/09/28 01:56:20 dbertrand Exp $

  name "Freeverb"
  
  include "emu_constants.inc"
  include "fv-routes.inc"
  include "fv-controls.inc"
  include "fv-basstreble.inc"
  
	; IO lines right/left
ior io
iol io
	

  ; No room reflection support - load full set of Freeverb filters and put 
  ; them into ITRAM first
  include "fv-filters.inc"
  ; delay lines for channel & reverb predelay will use XTRAM
dlyr delay &2   
dlyl delay &2   


writer twrite dlyr,0
writel twrite dlyl,0
oreadr tread dlyr,64     ; use 64 samples to avoid some TRAM glitches
oreadl tread dlyl,64
revreadr tread dlyr,64
revreadl tread dlyl,64
	
input dyn 1         ; wet reverb input [== (inl+inr)*gain ]

dly_b2	sta 0,0   ; storage for second bass/treble filter
dly_t2	sta 0,0


dly_b3	sta 0,0   
dly_t3	sta 0,0
dly_b4	sta 0,0   
dly_t4	sta 0,0

reflr dyn 2
refll dyn 2
reverbr dyn 1
reverbl dyn 1
ptr dyn 2
ptl dyn 2
  




  

  ;;; update TRAM read addresses from control GPRs
  acc3 oreadr.a,delay_r,writer.a,C_0
  acc3 oreadl.a,delay_l,writel.a,C_0
  acc3 revreadr.a,revdelay,writer.a,C_0
  acc3 revreadl.a,revdelay,writel.a,C_0

  ;;; init reverb outputs (and clear ACCUM for code below)
  macs fvrev_l,C_0,C_0,C_0
  macs fvrev_r,C_0,C_0,C_0

  ;;; accumulate reverb inputs ( predelayed R+L * revgain )
  ;;; and at the same time pass input to output w/delay
  macmv ior,oreadr,revreadr,revgain
  macs input,ACCUM,revreadl,revgain
	acc3 iol,oreadl,C_0,C_0
  acc3 writer,ior,C_0,C_0
  acc3 writel,iol,C_0,C_0

  ;;; apply & accumulate comb filters
  do_comb_filters fvrev_l,fvrev_r
  
  ;;; apply allpass filters
  do_allpass_filters fvrev_l,fvrev_r
  
  ;;; feed accumulated values to outputs, multiplying by wet & dry controls
  interp tmp,fvrev_l,wet1,fvrev_r
  interp tmpout,fvrev_r,wet1,fvrev_l
  macs fvrev_l,tmp,revreadl,dry
  macs fvrev_r,tmpout,revreadr,dry
  
  ;;; apply bass/treble controls to output
  test revdefeat
  bne .skipbasstreble
  basstreble fvrev_l,fvrev_l,revbass,revtreble,dly_b1,dly_t1
  basstreble fvrev_r,fvrev_r,revbass,revtreble,dly_b2,dly_t2
.skipbasstreble

  ;;; reset level meters at specified interval (use DBAC to track it)
  andxor tmp,DBAC,level_interval,C_0
  bne .skipreset
  acc3 maxlev_fr,C_0,C_0,C_0
  acc3 maxlev_fl,C_0,C_0,C_0
  acc3 maxlev_rr,C_0,C_0,C_0
  acc3 maxlev_rl,C_0,C_0,C_0
.skipreset
  

  ;;; apply reflection levels and bass/treble
  macs reflr,C_0,fvrefl_fr,refl_f
  macs refll,C_0,fvrefl_fl,refl_f
  
  macs reflr,reflr,fvrefl_rr,refl_f   ; two-speaker mode - add in other line
  macs refll,refll,fvrefl_rl,refl_f
  
  
  ;;; apply reverb levels
  macs  reverbr,C_0,fvrev_r,reverb_f
  macs  reverbl,C_0,fvrev_l,reverb_f
  

  

  ;;; write in+reverb_reflections to output    
  ;;; use macmv accumulation for extra precision
makeoutput MACRO io,refl,reverb,passthru
  macs C_0,C_0,C_0,C_0
  macmv tmp,tmp,refl,C_max
  
    macmv tmp,C_0,io,ptf_level
  
  macs io,ACCUM,reverb,C_max
  ENDM
  makeoutput ior,reflr,reverbr,ptr
  makeoutput iol,refll,reverbl,ptl
  
  ;;; maintain the maximum level 
maxlevel MACRO io,maxlev
  tstneg tmp,io,io,C_0             ; tmp = abs(io)
  limit maxlev,tmp,tmp,maxlev  ; maxlevel=max(tmp,maxlevel)
  ENDM
  maxlevel ior.o,maxlev_fr
  maxlevel iol.o,maxlev_fl
  
  END
