.packageName <- "sound"
.First.lib <- function(lib, pkg) {
  if (is.null(WavPlayer()))
    setWavPlayer()
}

setWavPlayer <- function(command=NULL){
  flag <- command
  if (is.null(flag)) command <- findWavPlayer()
  if (is.null(command)) {
    warning(paste("To play sounds you need to select a wav file player first.\n",
                  "For more information type '?setWavPlayer'.\n", sep=""))
  }
  else {
    if (!is.character(command)) stop("Argument 'command' must be a vector of character strings.")
    for (trycommand in command){
      op <- options(warn=2)
      if (trycommand=="mplay32 /play") {
        status <- try(system(paste(trycommand," /close ",.path.package(package = "sound"),"/data/testsample.wav",sep="")))
      }
      else {
        status <- try(system(paste(trycommand," ",.path.package(package = "sound"),"/data/testsample.wav",sep="")))
      }
      options(op)
      if (!inherits(status,"try-error")) {
        options(wavplayer=trycommand)
        return(paste("WAV file player '",trycommand,"' linked successfully.",sep=""))
      }
    }
    singplur <- sum(length(command)>1)+1
    if (is.null(flag)) {
      warning(paste("======================================================================",
                    "Couldn't run the default wav file play commands for your system.\n",
                    "Make sure they can be used as 'command soundfile.wav' and\n",
                    "then type 'setWavPlayer()'.\n",
                    "For more information - also about selecting an individual wav file player -\n",
                    "type '?setWavPlayer'.\n",
                    "======================================================================\n", sep="") )
    }
    else {
      warning(paste("============================================================================\n",
                    "Couldn't run ",c("the given command","any of the given commands")[singplur],".\n",
                    "Make sure ",c("it","they")[singplur]," can be used as 'command soundfile.wav' and then ",
                    "try it again.\nFor more information type '?setWavPlayer'.\n",
                    "============================================================================\n", sep="") )
    }
  }
  invisible(NULL)
}

WavPlayer <- function() {
  return(options()$wavplayer)
}

findWavPlayer <- function(){
  command <- switch(R.Version()$os,
	            "linux-gnu" = c("play","playwave"),
 	            "Win32"     = "mplay32 /play",
                    "mingw32"   = "mplay32 /play",
                    default     = NULL)
  if (is.null(command)) warning("No standard wav player known for your system.\n")
  return(command)
}

#=========================================================================
#                             create objects
#=========================================================================

as.Sample <- function(sound,rate=44100,bits=16){
  if (mode(sound)!="numeric")
    stop("Argument 'sound' must be a numeric vectors.")
  if (mode(rate)!="numeric" || rate<1000 || rate>48000)
    stop("Parameter 'rate' must be an number between 1000 and 48000.")
  if (mode(bits)!="numeric" || bits!=8 && bits!=16)
    stop("Parameter 'bits' must be 8 or 16.")
  if (is.null(dim(sound)))
    sound <- matrix(sound,nrow=1)
  if (dim(sound)>2){
    warning("Argument 'sound' has more than two rows. Only the first two are used.")
    sound <- sound[1:2,]
  }
  Sample <- list(sound=sound,rate=rate,bits=bits)
  class(Sample)<-"Sample"
  return(Sample)
}

#=========================================================================
#                        check for Sample object
#=========================================================================

is.Sample <- function(s,argname="'s' "){
  if (!is.null(class(s)) && class(s)=="Sample") return(list(test=TRUE))
  if (mode(s)!="character") return(list(test=FALSE,
      error=paste("Argument ",argname,"must be a Sample object or the name of a wav file.",sep="")))
  if (substr(s,nchar(s)-3,nchar(s))!=".wav") return(list(test=FALSE,error="Filename must have the extension .wav."))
  if (file.access(s)==-1) return(list(test=FALSE,error="File not found."))
  if (file.access(s,4)==-1) return(list(test=FALSE,error="No read permission for this file."))
  else return(list(test=TRUE))
}

#=========================================================================
#                           load / save samples
#=========================================================================

loadSample <- function(filename,filecheck=TRUE){
  if (!is.null(class(filename)) && class(filename)=="Sample") return(filename)
  if (mode(filename)!="character")
    stop("Argument 'filename' must be a character string.")
  if (substr(filename,nchar(filename)-3,nchar(filename))!=".wav")
    stop("Filename must have the extension .wav.")
  if (filecheck){
    if (file.access(filename)==-1)
      stop("File not found.")
    if (file.access(filename,4)==-1)
      stop("No read permission for this file.")
  }

  fileR <- file(filename,"rb")
              readBin(fileR,"integer",n=22,size=1)
  channels <- readBin(fileR,"integer",size=2)
  rate     <- readBin(fileR,"integer")
              readBin(fileR,"integer",n=6,size=1)
  bits     <- readBin(fileR,"integer",size=2)
              readBin(fileR,"integer",n=4,size=1)
  Length   <- readBin(fileR,"integer")
  if (bits==8)
      data <- readBin(fileR,"integer",n=Length  ,size=1,signed=FALSE)
  else
      data <- readBin(fileR,"integer",n=Length/2,size=2,signed=TRUE )
  close(fileR)

  if (bits==8)
    data   <- data/128-1
  else
    data   <- data/32768

  if (channels==2)
    dim(data) <- c(channels,length(data)/channels)

  return(as.Sample(data,rate,bits))
}

saveSample <- function(s,filename,overwrite=FALSE){
  if (is.null(class(s)) || class(s)!="Sample")
    stop("Argument 's' must be of class 'Sample'.")
  if (mode(filename)!="character")
    stop("Argument 'filename' must be a character string.")
  if (substr(filename,nchar(filename)-3,nchar(filename))!=".wav")
    stop("Filename must have the extension .wav.")
  if (file.access(filename)==0) {
    if (overwrite==FALSE) {cat(filename,"\n"); stop("File exists.")}
    if (file.remove(filename)==FALSE)
      stop("File exists and is protected against deletion.")
  }

  if (channels(s)==1) {data<-sound(s)[1,]}
    else  {data <- array(sound(s),dim=c(1,2*sampleLength(s)))}

  if (bits(s)==8) data <- data*127+128
  else data <- data*32767

  dataLength <- length(data)*bits(s)/8

  fileW <- file(filename,"wb")
  writeChar("RIFF",fileW,eos=NULL)                           # "RIFF"
  close(fileW)

  fileA <- file(filename,"ab")
  writeBin(as.integer(36+dataLength),fileA)                  # number of following bytes
  writeChar("WAVEfmt ",fileA,eos=NULL)                       # "WAVE"; "fmt "
  writeBin(as.integer(16),fileA)                             # always 16
  writeBin(as.integer(1),fileA,size=2)                       # always 1
  writeBin(as.integer(channels(s)),fileA,size=2)             # 1=mono / 2=stereo
  writeBin(as.integer(rate(s)),fileA)                        # sample rate
  writeBin(as.integer(rate(s)*channels(s)*bits(s)/8),fileA)  # bytes/second
  writeBin(as.integer(channels(s)*bits(s)/8),fileA,size=2)   # bytes/sample
  writeBin(as.integer(bits(s)),fileA,size=2)                 # bits/sample

  writeChar("data",fileA,eos=NULL)                           # "data"
  writeBin(as.integer(dataLength),fileA)                     # length of data in bytes
  writeBin(as.integer(data),fileA,size=bits(s)/8)            # data
  close(fileA)
}

#=========================================================================
#                             play sample
#=========================================================================

play <- function(s,stay=FALSE,command=WavPlayer()){
  UseMethod("play")
}

play.default <- function(filename,stay=FALSE,command=WavPlayer()){
  if (is.null(command)) {
    stop(paste("No wav file player selected.\n",
               "To play sounds you need to select a wav file player first.\n",
               "For more information type '?setWavPlayer'.", sep=""))
  }
  sampletest <- is.Sample(filename,argname="")
  if (!sampletest$test) stop(sampletest$error)
  if (stay==FALSE && command=="mplay32 /play") command <- paste(command,"/close")
  system(paste(command,filename))
  invisible(NULL)
}

play.Sample <- function(s,stay=FALSE,command=WavPlayer()){
  if (is.null(command)) {
    stop(paste("No wav file player selected.\n",
               "To play sounds you need to select a wav file player first.\n",
               "For more information type '?setWavPlayer'.", sep=""))
  }
  filename <- paste(tempfile("tempSound"),".wav",sep="")
  saveSample(s,filename)
  play(filename,stay=stay,command=command)
  if (stay==FALSE) {file.remove(filename)}
  invisible(NULL)
}

#=========================================================================
#                         display sample data
#=========================================================================

print.Sample <- function(x,...){
  sampletest <- is.Sample(x,argname="'x' ")
  if (!sampletest$test) stop(sampletest$error)
  s <- loadSample(x,filecheck=FALSE)
  cat("type      : ",c("mono","stereo")[channels(s)],"\n",
      "rate      : ",rate(s)," samples / second\n",
      "quality   : ",bits(s)," bits / sample\n",
      "length    : ",sampleLength(s)," sample",ifelse(sampleLength(s)==1,"\n","s\n"),
      "R memory  : ",sampleLength(s)*channels(s)*4," bytes\n",
      "HD memory : ",sampleLength(s)*channels(s)*bits(s)/8+44," bytes\n",
      "duration  : ",round(duration(s),3)," second",ifelse(round(duration(s),3)==1,"\n","s\n"),sep="")
  invisible(NULL)
}

plot.Sample <- function(x,xlab="sample #",ylab=NULL,...){
  sampletest <- is.Sample(x,argname="'x' ")
  if (!sampletest$test) stop(sampletest$error)
  s <- loadSample(x,filecheck=FALSE)
  if (channels(s)==1) {
    if (is.null(ylab)) ylab <- "waveform"
    plot(sound(s)[1,],type="l",col="red" ,ylim=c(-1,1),xlim=sampleLength(s)*c(.04,1.04)/1.08,
         xlab=xlab,ylab=ylab,axes=FALSE,...)
    axis(1)
    axis(2,at=c(-1,0,1),labels=as.character(c(-1,0,1)))
    abline(h=0)
    abline(h=c(-1,1),lty="dashed")
    lines(par()$usr[1:2],y=c(rep(par()$usr[3],2)),xpd=TRUE)
  }
  else {
    op1 <- par(mfrow=c(2,1))
    op2 <- par(mar=c(2,4,4,2)+.1)
    if (is.null(ylab)) ylab <- c("left","right")   
    plot(sound(s)[1,],type="l",col="red",ylim=c(-1,1),xlim=sampleLength(s)*c(.04,1.04)/1.08,
         xlab="",ylab=ylab[min(2,length(ylab))],axes=FALSE,...)
    axis(1)
    axis(2,at=c(-1,0,1),labels=as.character(c(-1,0,1)))
    abline(h=0)
    abline(h=c(-1,1),lty="dashed")
    lines(par()$usr[1:2],y=c(rep(par()$usr[3],2)),xpd=TRUE)
    par(op2)

    op3 <- par(mar=c(5,4,1,2)+.1)
    plotwithoutmain <- function(main,...){
      plot(sound(s)[2,],type="l",col="blue",ylim=c(-1,1),xlim=sampleLength(s)*c(.04,1.04)/1.08,
           xlab=xlab,ylab=ylab[1],axes=FALSE,main="",...)
    }
    plotwithoutmain(...)
    axis(1)
    axis(2,at=c(-1,0,1),labels=as.character(c(-1,0,1)))
    abline(h=c(0,par()$usr[1]))
    abline(h=c(-1,1),lty="dashed")
    lines(par()$usr[1:2],y=c(rep(par()$usr[3],2)),xpd=TRUE)
    par(op3)
    par(op1)
  }
  invisible(NULL)
}

#=========================================================================
#                            cut sample
#=========================================================================

"[.Sample" <- function(s,i){
  if (mode(i)!="numeric")
    stop("Index must be numeric.")
  ch <- channels(s)
  wave <- sound(s)[1:ch,i[!is.na(sound(s)[1,i])]]
  dim(wave) <- c(ch,length(wave)/ch)
  sound(s) <- wave
  return(s)
}

cutSample <- function(s,start,end){
  sampletest <- is.Sample(s)
  if (!sampletest$test) stop(sampletest$error)
  s <- loadSample(s,filecheck=FALSE)
  if (mode(start)!="numeric" || mode(end)!="numeric" || start<0 || end<0)
    stop("Parameters 'start' and 'end' must be a numeric >=0.")
  end <- min(end,duration(s))
  if (start>end)
    stop("Argument 'start' is larger than argument 'end'.")
  if (start>duration(s)){
    warning("Argument start is larger than duration of sample. Empty sample returned.")
    return(nullSample(rate(s),bits(s),channels(s)))
  }
  return(s[1+as.integer(start*rate(s)):as.integer(end*rate(s))])
}

#=========================================================================
#                        read / set basic properties
#=========================================================================

sound    <- function(s) {
  sampletest <- is.Sample(s)
  if (!sampletest$test) stop(sampletest$error)
  return(loadSample(s,filecheck=FALSE)$sound)
}

bits     <- function(s) {
  sampletest <- is.Sample(s)
  if (!sampletest$test) stop(sampletest$error)
  return(loadSample(s,filecheck=FALSE)$bits)
}

rate     <- function(s) {
  sampletest <- is.Sample(s)
  if (!sampletest$test) stop(sampletest$error)
  return(loadSample(s,filecheck=FALSE)$rate)
}

channels <- function(s) {
  sampletest <- is.Sample(s)
  if (!sampletest$test) stop(sampletest$error)
  return(dim(loadSample(s,filecheck=FALSE)$sound)[1])
}

sampleLength <- function(s) {
  sampletest <- is.Sample(s)
  if (!sampletest$test) stop(sampletest$error)
  return(length(sound(loadSample(s,filecheck=FALSE))[1,]))
}

duration <- function(s) {
  sampletest <- is.Sample(s)
  if (!sampletest$test) stop(sampletest$error)
  if (is.null(class(s))) s <- loadSample(s,filecheck=FALSE)
  return(sampleLength(s)/rate(s))
}

"sound<-" <- function(s,value){
  s$sound <- value
  return(s)
}

"bits<-" <- function(s,value){
  if (is.null(class(s)) || class(s)!="Sample")
    stop("Argument 's' must be of class 'Sample'.")
  if (mode(value)!="numeric" || (value!=8 && value!=16))
    stop("Number of bits must be 8 or 16.")
  else s$bits <- value
  return(s)
}

"rate<-" <- function(s,value){
  if (is.null(class(s)) || class(s)!="Sample")
    stop("Argument 's' must be of class 'Sample'.")
  if (mode(value)!="numeric" || value<1000 || value>48000)
    stop("Rate must be an number between 1000 and 48000.")
  if (rate(s)==value) return(s)
  ch <- channels(s)
  sound(s) <- sound(s)[,as.integer(seq(1,sampleLength(s)+.9999,by=rate(s)/value))]
  dim(sound(s)) <- c(ch,length(sound(s))/ch)
  s$rate <- value
  return(s)
}

"channels<-" <- function(s,value){
  if (is.null(class(s)) || class(s)!="Sample")
    stop("Argument 's' must be of class 'Sample'.")
  if (mode(value)!="numeric" || !(value==1 || value==2))
    stop("Number of channels must be 1 or 2.")
  if (channels(s)==value) return(s)
  else {
    if (value==1){
      sound(s) <- (sound(s)[1,] + sound(s)[2,])/2
      dim(sound(s)) <- c(1,length(sound(s)))
    }
    else {
      sound(s) <- rbind(sound(s),sound(s))
    }
    return(s)
  }
}

"sampleLength<-" <- function(s,value){
  UseMethod("sampleLength<-")
}

"sampleLength<-.Sample" <- function(s,value){
  if (is.null(class(s)) || class(s)!="Sample")
    stop("Argument 's' must be of class 'Sample'.")
  if (mode(value)!="numeric" || value<1)
    stop("Sample length must be a positive integer.")
  if (sampleLength(s)>value){
      ch <- channels(s)
      sound(s) <- sound(s)[,1:value]
      dim(sound(s)) <- c(ch,value)
  }
  else sound(s) <- cbind(sound(s),matrix(0,channels(s),value-sampleLength(s)))
  return(s)
}

"duration<-" <- function(s,value){
  if (is.null(class(s)) || class(s)!="Sample")
    stop("Argument 's' must be of class 'Sample'.")
  if (mode(value)!="numeric" || value<=0)
    stop("Duration must be a positive number.")
  sampleLength(s) <- as.integer(value*rate(s))
  return(s)
}

setBits <- function(s,b){
  sampletest <- is.Sample(s)
  if (!sampletest$test) stop(sampletest$error)
  if (mode(b)!="numeric" || (b!=8 && b!=16))
    stop("Number of bits must be 8 or 16.")
  if (is.null(class(s))) s <- loadSample(s,filecheck=FALSE)
  bits(s) <- b
  return(s)
}

setRate <- function(s,r){
  sampletest <- is.Sample(s)
  if (!sampletest$test) stop(sampletest$error)
  if (mode(r)!="numeric" || r<1000 || r>48000)
    stop("Rate must be a number between 1000 and 48000.")
  if (is.null(class(s))) s <- loadSample(s,filecheck=FALSE)
  rate(s) <- r
  return(s)
}

setChannels <- function(s,c){
  sampletest <- is.Sample(s)
  if (!sampletest$test) stop(sampletest$error)
  if (mode(c)!="numeric" || !(c==1 || c==2))
    stop("Number of channels must be 1 or 2.")
  if (is.null(class(s))) s <- loadSample(s,filecheck=FALSE)
  channels(s) <- c
  return(s)
}

setSampleLength <- function(s,l){
  sampletest <- is.Sample(s)
  if (!sampletest$test) stop(sampletest$error)
  if (mode(l)!="numeric" || l<1)
    stop("Sample length must be a positive integer.")
  if (is.null(class(s))) s <- loadSample(s,filecheck=FALSE)
  sampleLength(s) <- l
  return(s)
}

setDuration <- function(s,d){
  sampletest <- is.Sample(s)
  if (!sampletest$test) stop(sampletest$error)
  if (mode(d)!="numeric" || d<=0)
    stop("Duration must be a positive number.")
  if (is.null(class(s))) s <- loadSample(s,filecheck=FALSE)
  duration(s) <- d
  return(s)
}

fitSampleParameters <- function(s1,s2){
  sampletest <- is.Sample(s1,argname="s1 ")
  if (!sampletest$test) stop(sampletest$error)
  sampletest <- is.Sample(s2,argname="s2 ")
  if (!sampletest$test) stop(sampletest$error)
  if (is.null(class(s1))) s1 <- loadSample(s1,filecheck=FALSE)
  if (is.null(class(s2))) s2 <- loadSample(s2,filecheck=FALSE)
  rate(s1) <- max(rate(s1),rate(s2))
  rate(s2) <- max(rate(s1),rate(s2))
  channels(s1) <- max(channels(s1),channels(s2))
  channels(s2) <- max(channels(s1),channels(s2))
  bits(s1) <- max(bits(s1),bits(s2))
  bits(s2) <- max(bits(s1),bits(s2))
  return(list(s1,s2))
}

#=========================================================================
#                    binary operations: +, *, /, append
#=========================================================================

Ops.Sample <- function(s1,s2){
  if (.Generic=="+"){
    if (is.null(class(s1)) || is.null(class(s2)) || class(s1)!="Sample" || class(s2)!="Sample")
      stop("Arguments must be of class 'Sample'.")
    s <- fitSampleParameters(s1,s2)
    s1 <- s[[1]]
    s2 <- s[[2]]

    m <- max(sampleLength(s1),sampleLength(s2))
    s1 <- setSampleLength(s1,m)
    s2 <- setSampleLength(s2,m)

    sound(s1) <- sound(s1) + sound(s2)

    return(s1)
  }

  if (.Generic=="-"){
    if (missing(s2)){
      sound(s1) <- -sound(s1)
      return(s1)
    }
    else return(s1+(-s2))
  }

  if (.Generic=="*"){
    if (mode(s2)=="numeric") return(s2*s1)
    else if (mode(s1)=="numeric"){
      sound(s2) <- s1*sound(s2)
      return(s2)
    }
    else if (!is.null(class(s1)) && !is.null(class(s2)) && class(s1)=="Sample" && class(s2)=="Sample"){
      s <- fitSampleParameters(s1,s2)
      s1 <- s[[1]]
      s2 <- s[[2]]

      m <- max(sampleLength(s1),sampleLength(s2))
      sampleLength(s1) <- m
      sampleLength(s2) <- m

      sound(s1) <- sound(s1) * sound(s2)

      return(s1)
    }
    else stop("Arguments must be numeric or of class 'Sample'.")
  }

  if (.Generic=="/"){
    if(mode(s2)!="numeric") stop("Second argument must be numeric.")
    else return(1/s2*s1)
  }
}

sum.Sample <- function(s1,s2,...){
  sampletest <- is.Sample(s1,argname="")
  if (!sampletest$test) stop(sampletest$error)
  if(missing(s2)) {
    return(loadSample(s1,filecheck=FALSE))
  }
  return(loadSample(s1,filecheck=FALSE)+sum.Sample(s2,...))
}

prod.Sample <- function(s1,s2,...){
  sampletest <- is.Sample(s1,argname="")
  if (!sampletest$test) stop(sampletest$error)
  if(missing(s2)) {
    return(loadSample(s1,filecheck=FALSE))
  }
  return(loadSample(s1,filecheck=FALSE)*prod.Sample(s2,...))
}

appendSample <- function(s1,s2,...){
  if (is.null(s1) && !missing(s2)) return(appendSample(s2,...))
  sampletest <- is.Sample(s1,argname="")
  if (!sampletest$test) stop(sampletest$error)
  if (missing(s2)){
    return(loadSample(s1,filecheck=FALSE))
  }
  s2 <- appendSample(s2,...)
  s  <- fitSampleParameters(loadSample(s1,filecheck=FALSE),s2)
  sound(s[[1]]) <- cbind(sound(s[[1]]),sound(s[[2]]))
  return(s[[1]])
}

#=========================================================================
#                          panorama operations
#=========================================================================

stereo <- function(sLeft,sRight,pan=50){
  sampletest <- is.Sample(sLeft,argname="sLeft ")
  if (!sampletest$test) stop(sampletest$error)
  sampletest <- is.Sample(sRight,argname="sRight ")
  if (!sampletest$test) stop(sampletest$error)
  if (mode(pan)!="numeric" || abs(pan)>50)
    stop("Parameter 'pan' must be numeric between -50 and 50.")
  sLeft  <- setChannels(sLeft ,1)
  sRight <- setChannels(sRight,1)
  s      <- fitSampleParameters(sLeft,sRight)
  sLeft  <- s[[1]]
  sRight <- s[[2]]
  m <- max(sampleLength(sLeft),sampleLength(sRight))
  sampleLength(sLeft)  <-  m
  sampleLength(sRight) <-  m
  sound(sLeft) <- rbind(sound(sLeft),sound(sRight))
  sLeft <- panorama(sLeft,pan=pan)
  return(sLeft)
}

panorama <- function(s,pan) {
  sampletest <- is.Sample(s)
  if (!sampletest$test) stop(sampletest$error)
  if (mode(pan)!="numeric" || abs(pan)>50)
    stop("Parameter 'pan' must be numeric between -50 and 50.")
  s <- loadSample(s,filecheck=FALSE)
  if(channels(s)==1 || pan==50) return(s)
  if(pan==-50) return(mirror(s))
  sl <- sound(s)[1,]
  sound(s)[1,]  <- (50+pan)*sl           + (50-pan)*sound(s)[2,]
  sound(s)[2,]  <- (50+pan)*sound(s)[2,] + (50-pan)*sl
  return(s/100)
}

mirror <- function(s){
  sampletest <- is.Sample(s)
  if (!sampletest$test) stop(sampletest$error)
  s <- loadSample(s,filecheck=FALSE)
  if (channels(s)==2) sound(s) <- sound(s)[2:1,]
  return(s)
}

left <- function(s){
  sampletest <- is.Sample(s)
  if (!sampletest$test) stop(sampletest$error)
  s <- loadSample(s,filecheck=FALSE)
  if (channels(s)==1) return(s)
  sound(s) <- matrix(sound(s)[1,],nrow=1)
  return(s)
}

right <- function(s){
  sampletest <- is.Sample(s)
  if (!sampletest$test) stop(sampletest$error)
  s <- loadSample(s,filecheck=FALSE)
  if (channels(s)==1) return(s)
  sound(s) <- matrix(sound(s)[2,],nrow=1)
  return(s)
}

#=========================================================================
#                          transform sample
#=========================================================================

reverse <- function(s){
  sampletest <- is.Sample(s)
  if (!sampletest$test) stop(sampletest$error)
  s <- loadSample(s,filecheck=FALSE)
  for (i in 1:channels(s)){
    sound(s)[i,] <- sound(s)[i,sampleLength(s):1]
  }
  return(s)
}

pitch <- function(s,semitones){
  sampletest <- is.Sample(s)
  if (!sampletest$test) stop(sampletest$error)
  s <- loadSample(s,filecheck=FALSE)
  if (mode(semitones)!="numeric") stop("Parameter 'semitones' must be numeric.")
  return(s[as.integer(seq(1,sampleLength(s),by=2^(semitones/12)))])
}

cutSampleEnds <- function(s){
  sampletest <- is.Sample(s)
  if (!sampletest$test) stop(sampletest$error)
  s <- loadSample(s,filecheck=FALSE)
  i <- 1
  while (!(sound(s)[1,i]<=0 && sound(s)[1,i+1]>0)) i <- i+1
  j <- sampleLength(s)
  while (!(sound(s)[1,j]>=0 && sound(s)[1,j-1]<0)) j <- j-1
  return(s[(i+1):(j-1)])
}

normalize <- function(s,level=1){
  sampletest <- is.Sample(s)
  if (!sampletest$test) stop(sampletest$error)
  s <- loadSample(s,filecheck=FALSE)
  if (mode(level)!="numeric" || level>1 || level<0) stop("Parameter 'level' must be a number between 0 and 1.")
  return(s/max(abs(sound(s)))*level)
}

center <- function(s){
  sampletest <- is.Sample(s)
  if (!sampletest$test) stop(sampletest$error)
  s <- loadSample(s,filecheck=FALSE)
  for (i in 1:channels(s))
    sound(s)[i,] <- sound(s)[i,]-mean(sound(s)[i,])
  class(s)<-"Sample"
  return(s)
}

noSilence <- function(s,level=0,start=TRUE,end=TRUE){
  sampletest <- is.Sample(s)
  if (!sampletest$test) stop(sampletest$error)
  s <- loadSample(s,filecheck=FALSE)
  if (mode(level)!="numeric" || level<0) stop("Parameter 'level' must be a numeric >=0.")
  i <- 1
  j <- sampleLength(s)
  if (start) {while (max(abs(sound(s)[,i]))<=level && i<j) i <- i+1}
  if (end)   {while (max(abs(sound(s)[,j]))<=level && j>i) j <- j-1}
  if (j==i){
    warning("Empty sample returned.")
    return(nullSample(rate(s),bits(s),channels(s)))
}
  return(s[i:j])
}

#=========================================================================
#                           basic wave forms
#=========================================================================

Sine <- function(freq,dur,rate=44100,bits=16,channels=1){
  if (mode(freq)!="numeric")
    stop("Parameter 'freq' must be numeric.")
  if (mode(dur)!="numeric" || dur<=0)
    stop("Parameter 'dur' must be positive numeric.")
  Sample <- as.Sample(sin(seq(0,freq*dur*2*pi,length=rate*dur)),rate,bits)
  Sample <- setChannels(Sample,channels)
  return(Sample)
}

Sawtooth <- function(freq,dur,rate=44100,bits=16,channels=1,reverse=FALSE){
  if (mode(freq)!="numeric")
    stop("Parameter 'freq' must be numeric.")
  if (mode(dur)!="numeric" || dur<=0)
    stop("Parameter 'dur' must be positive numeric.")
  sound <- (seq(0,2*freq*dur,length=rate*dur)%%2-1)
  if (reverse==TRUE) sound <- sound[length(sound):1]
  Sample <- as.Sample(sound,rate,bits)
  Sample <- setChannels(Sample,channels)
  return(Sample)
}

Square <- function(freq,dur,rate=44100,bits=16,channels=1,upPerc=50){
  if (mode(freq)!="numeric")
    stop("Parameter 'freq' must be numeric.")
  if (mode(dur)!="numeric" || dur<=0)
    stop("Parameter 'dur' must be positive numeric.")
  if (mode(upPerc)!="numeric" || upPerc<0 || upPerc >100)
    stop("Parameter 'upPerc' must be between 0 and 100.")
  sound <- sign((seq(0,freq*dur,length=rate*dur)%%1-(1-upPerc/100)))
  Sample <- as.Sample(sound,rate,bits)
  Sample <- setChannels(Sample,channels)
  return(Sample)  
}

Noise <- function(dur,rate=44100,bits=16,channels=1){
  if (mode(dur)!="numeric" || dur<=0)
    stop("Parameter 'dur' must be positive numeric.")
  if (channels==1) s <- as.Sample(runif(rate*dur,min=-1,max=1),rate,bits)
  else s <- as.Sample(rbind(runif(rate*dur,min=-1,max=1),runif(rate*dur,min=-1,max=1)),rate,bits)
  return(s)
}

Silence <- function(dur,rate=8000,bits=8,channels=1){
  if (mode(dur)!="numeric" || dur<=0)
    stop("Parameter 'dur' must be positive numeric.")
  else return(as.Sample(matrix(0,channels,dur*rate),rate,bits))
}

nullSample <- function(rate=44100,bits=16,channels=1){
  return(as.Sample(matrix(0,channels,1),rate,bits))
}
