# onsetDetectionControl() Creates a control object for onset detection.
#
# INPUT: 	norm.amplit: a logical parameter. If TRUE, the signal amplitude is divided by the absolute maximum value. 
#						In this case, the onset detection is not online. Default is FALSE
#			window.size: number of samples for splitting the signal. Should be power of two! Default is 2048. Integer parameter.
#		 	hop.size: 	number of samples between two neighboring windows. Should lie between window.size/10 and window size. 
#						Default is window.size/2. Integer parameter.
#			sampling.rate: sampling rate of audio recording. Default is 44100. Integer parameter.
#			window.fun: windowing functions from signal R-package signal. Possible values are: c("hamm", "hann", "black", "gauss", "rect"). 
#						Default is "hann".
#			aw.r:  		floor parameter of adaptive whitening. Should lie between 10^(-6) and 0.2. 
#						If 999, no adaptive whitening is applied. Default is 999. 
#			aw.m: 		memory parameter of adaptive whitening. Should lie between 22 and 446 ms. 
#						If 999, no adaptive whitening is applied. Default is 999.
#			spec.filter:  If "yes", a spectral filter will be applied to the spectral magnitude of the signal.
#						If "no", no filtering is applied. Default is "no".
#			spec.log: 	an integer parameter. If "yes", the spectral magnitude of the signal will be logarithmized.
#						If "no", no logarithmizing is applied. Default is "no".
#			log.lambda:	compression parameter for logarithmizing the spectral magnitude. Should lie between 1 and 20
#						Default is 1.
#			odf:  		onset detection function to be used. Possibilities are: c("ZCRate", "AMax", "AMaxA", "AEnerg", "AEnergA", 
#                                       "HFCont", "HFContA", "GFCont", "GFContA", "SCentr", "SSpread", "SSkew",
#                                       "SFlux", "SFluxEucl", "PDev", "WPDev", "CDom", "RCDom"). 
#						Default is "SFlux".
#			smooth.alpha: smoothing parameter for exponential smoothing. Should lie between 0 and 1. Default is 0.8.
#			thresh.fun: thresholding function. Possible values are: c("median", "mean", "quantile"). 
#						Default is "mean".
#			thresh.lambda: multiplicative parameter of thresholding function (important if thresh.fun == "median" or hresh.fun == "mean").
#						Default is 0.3.
#			thresh.delta: additive parameter of thresholding function (important if thresh.fun == "median" or hresh.fun == "mean").
#						Default is 2.
#			 thresh.quantile: quantile parameter of thresholding function (important if thresh.fun == "quantile").
#						Default is 0.95.
#			thresh.time.left: time (in seconds) in the previous signal for computing the thresholding function. 
#						Default is 0.2 s.
#			thresh.time.right:	time (in seconds) in the future signal for computing the thresholding function. 
#						Default is 0.2 s.
#			 onset.time.left: time (in seconds) in the previous signal for localizing the tone onsets. 
#						Default is 0.1 s.
#			onset.time.right: time (in seconds) in the future signal for localizing the tone onsets. 
#						Default is 0.1 s.
#			onset.time.min.dist: minimal distance in seconds between two onsets. Default is 0.05 s.
#			time.onset.shift: 	time in seconds for shifting the estimated onset times. Could also be negative.
#						Default is 0 s.
#			tolerance: 	time tolerance for computing the F-value. Default is 0.025 s.

# OUTPUT: control: a control object (list)


onsetDetectionControl = function(norm.amplit = FALSE,
								 window.size = 2048,
                                 hop.size = window.size/2,
                                 sampling.rate = 44100L,
                                 window.fun = "hann",
                                 aw.r = 999,
                                 aw.m = 999,
								 spec.filter = "no",
								 spec.log = "no",
								 log.lambda = 1,
                                 odf = "SFlux",
                                 smooth.alpha = 0.8,
                                 thresh.fun = "mean",
                                 thresh.lambda = 0.3,
								 thresh.delta = 2,
                                 thresh.quantile = 0.95,
                                 thresh.time.left = 0.2,
                                 thresh.time.right = 0.2,
                                 onset.time.min.dist = 0.05,
                                 onset.time.left = 0.1,
                                 onset.time.right = 0.1,
								 time.onset.shift = 0,
                                 tolerance = 0.025
                                ) {
  
    if (!is.logical(norm.amplit)) {
    stop("'norm.amplit' has to be logical")
  }
  
  if (!is.numeric(window.size)) {
    stop("'window.size' has to be numeric")
  }
  if (window.size<0 | hop.size<0 ) {
    stop("'window.size' and 'hop.size' should be >0!")
  }
  if (!is.numeric(hop.size)) {
    stop("'hop.size' has to be numeric")
  }
  if (!is.numeric(aw.r)) {
    stop("'aw.r' has to be numeric")
  }
  if (!is.numeric(aw.m)) {
    stop("'aw.m' has to be numeric")
  }
  if (!is.integer(sampling.rate)) {
    stop("'sampling.rate' has to be integer")
  }
  
  power=log(window.size,base=2)
  if (ceiling(power)!=floor(power)) {
    stop("'window.size' has to be a power of 2!")
  } 
  
  if (hop.size>window.size) {
    warning("'hop.size' should not exceed the 'window.size'. It is now set to the default value")
    hop.size=window.size/2
  } 
  
  if (hop.size< (window.size)/10) {
    warning("'hop.size' should not be smaller than 'window.size'/10. It is now set to the default value")
    hop.size=window.size/2
  }
  
  if(!(window.fun %in% c("hamm", "hann", "black", "gauss", "rect"))){
    stop("possible settings for 'window.fun' are: hamm, hann, black, gauss or rect.")
  }
  
  if(!(spec.filter %in% c("yes", "no"))){
    stop("possible settings for 'spec.filter' are: yes, no.")
  }
  
  if(!(spec.log %in% c("yes", "no"))){
    stop("possible settings for 'spec.log' are: yes, no.")
  }
  
   if (!is.numeric(log.lambda)) {
    stop("'log.lambda' has to be numeric")
  }
  
  if (log.lambda < 1) {
    warning("'log.lambda' should be more than 1. It is now set to 1")
  } 
  
  if(!(odf %in% c("ZCRate", "AMax", "AMaxA", "AEnerg", "AEnergA", 
                                       "HFCont", "HFContA", "GFCont", "GFContA", "SCentr", "SSpread", "SSkew",
                                       "SFlux", "SFluxEucl", "PDev", "WPDev", "CDom", "RCDom"))){
    stop("possible settings for 'odf' are: ZCRate, AMax, AMaxA, AEnerg, AEnergA, 
                                       HFCont, HFContA, GFCont, GFContA, SCentr, SSpread, SSkew,
                                       SFlux, SFluxEucl, PDev, WPDev, CDom, RCDom")
   }
	
  if (!is.numeric(smooth.alpha)) {
    stop("'smooth.alpha' has to be numeric")
  }
  
  if (smooth.alpha < 0 | smooth.alpha > 1) {
    warning("'smooth.alpha' should lie in [0,1]. It is now set to 0.8")
  } 
  
  if(!(thresh.fun %in% c("mean", "median", "quantile"))){
    stop("possible settings for 'spec.filter' are: mean, median, quantile.")
  }
  
  if (!is.numeric(thresh.lambda)) {
    stop("'thresh.lambda' has to be numeric")
  }
  
    if (!is.numeric(thresh.delta)) {
    stop("'thresh.lambda' has to be numeric")
  }
  
  if (!is.numeric(thresh.quantile)) {
    stop("'thresh.quantile' has to be numeric")
  }
  
  if (!is.numeric(thresh.time.left)) {
    stop("'thresh.time.left' has to be numeric")
  }
  
  if (!is.numeric(thresh.time.right)) {
    stop("'thresh.time.right' has to be numeric")
  }
  
   if (!is.numeric(onset.time.left)) {
    stop("'onset.time.left' has to be numeric")
  }
  
  if (!is.numeric(onset.time.right)) {
    stop("'onset.time.right' has to be numeric")
  }
  
  if (!is.numeric(onset.time.min.dist)) {
    stop("'onset.time.min.dist' has to be numeric")
  }
  
  if (!is.numeric(time.onset.shift)) {
    stop("'time.onset.shift' has to be numeric")
  }
  
  if (!is.numeric(tolerance)) {
    stop("'tolerance' has to be numeric")
  }

  control = list(norm.amplit = norm.amplit,
				window.size = window.size,
                hop.size = hop.size,
                sampling.rate = sampling.rate,
                window.fun = window.fun,
			    log.lambda = log.lambda,
			    spec.filter = spec.filter,
			    spec.log = spec.log,
                aw.r=aw.r,
                aw.m=aw.m,
                odf=odf,
                smooth.alpha=smooth.alpha,                               
                thresh.fun=thresh.fun,
                thresh.lambda=thresh.lambda,
				thresh.delta=thresh.delta,
                thresh.quantile=thresh.quantile,
                thresh.time.left=thresh.time.left,
                thresh.time.right=thresh.time.right,
                onset.time.left=onset.time.left,
                onset.time.right=onset.time.right,
                onset.time.min.dist = onset.time.min.dist,
			    time.onset.shift = time.onset.shift,
                tolerance=tolerance)
  return(control)
}
