Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- fluxcapacitor <- function(mt=0.05 # maximum tolerance for bpm variantion
- ,mva=0.25 # maximum threshold for average ms variance
- ,mvs=0.5 # maximum threshold for single ms variance
- ,ti=0.005 # tolerance interval
- ,patch=FALSE # output to patch dir?
- ,pdir # patch dir
- ,sdir # song dir
- ,extreme=FALSE){ # if true, evaluate all solutions and select the best
- read.sm <- function(sdir){ # self-explanatory
- smi <- list.files(sdir,full.names=TRUE)[which(substr(list.files(sdir),nchar(list.files(sdir))-2,nchar(list.files(sdir)))==".sm")]
- if(length(smi)>0){return(sm <- readLines(smi))}
- }
- rowmerge <- function(sm # .sm file
- ,x){ # merge specified data on multiple lines
- s <- which(substr(sm,1,nchar(x)) == x)
- nb <- head(which(substr(sm,1,6) =="#NOTES"),1)
- f <- s + grep(";",sm[s:nb[1]])[1] - 1
- m1 <- sm[s:f]
- o <- m1[1]
- if(length(m1) > 1){
- for (i in 2:length(m1)) {
- o <- paste(o,m1[i], sep="")
- }
- } else {
- o <- m1[1]
- }
- o <- substr(o,nchar(x)+1,nchar(o)-1)
- }
- rowremove <- function(sm # .sm file
- ,x){ # remove excess data lines for specified data
- s <- which(substr(sm,1,nchar(x)) == x)
- nb <- head(which(substr(sm,1,6) =="#NOTES"),1)
- f <- s + grep(";",sm[s:nb[1]])[1] - 1
- if(s-f !=0){
- r <- (s+1):f
- names(sm) <- 1:length(sm)
- sm <- sm[!names(sm) %in% r]
- }
- sm
- }
- getfb <- function(sm){ #determines the final measure of the file (in beats)
- ns <- head(which(substr(sm,1,7)=="#NOTES:"),1)+6
- nf <- head(grep(";",sm[ns:length(sm)]),1)+ns
- fb <- length(c(0,which(substr(sm[ns:nf],1,1)==","),nf))*4
- }
- createbpmarray <- function(b # convert the bpmline into an array
- ,fb){ # removes bpms beyond the final beat; appends entry for fb
- a <- lapply(lapply(unlist(strsplit(b,",")),strsplit,"="),unlist)
- a <- cbind(unlist(lapply(a,"[",1)),unlist(lapply(a,"[",2)))
- rownames(a) <- 1:dim(a)[1]
- class(a) <- "numeric"
- a <- a[1:tail(which(a[,1]<fb),1),]
- a <- rbind(a,c(fb,2.6457))
- }
- createstoparray <- function(s # convert the stopline into an array
- ,fb){ # remove stops beyond the final beat
- if(s!=""){
- a <- lapply(lapply(unlist(strsplit(s,",")),strsplit,"="),unlist)
- a <- cbind(unlist(lapply(a,"[",1)),unlist(lapply(a,"[",2)))
- rownames(a) <- 1:dim(a)[1]
- class(a) <- "numeric"
- arm <- tail(which(a[,1]<fb),1)
- if(length(arm)>0){
- a <- a[1:arm,]
- }else{
- a <- NULL
- }
- }
- if(exists("a")){rbind(a,NULL)}else{NULL}
- }
- createmsarray <- function(ba #bpm array
- ,sa #stop array
- ,fb){ #builds msarray until final beat
- if(!missing(fb)){
- ba <- rbind(ba,c(fb,2.6457))
- }
- mt <- as.vector(0)
- for(i in 2:dim(ba)[1]){
- mt[i] <- ((ba[i]-ba[i-1])/(ba[i-1,2]/60))
- }
- ma <- cbind(cbind(ba,mt),cumsum(mt))
- if(!is.null(sa)){
- ma <- cbind(ma,0)
- for(i in 1:dim(sa)[1]){
- mas <- head(which(ma[,1]>=sa[i,1]),1)
- ma[mas:dim(ma)[1],5] <- ma[mas:dim(ma)[1],5]+sa[i,2]
- }
- ma[,4] <- ma[,4]+ma[,5]
- }
- ma[,3:4] <- cbind(c(ma[2:dim(ma)[1],3],0),c(ma[2:dim(ma)[1],4],0))
- ma
- }
- msvar <- function(x # original msarray
- ,y){ # compares x to new msarray (y)
- y <- rbind(y,NULL)
- ex <- x[,1][x[,1] %in% y[,1]==FALSE]
- if(length(ex)!=0){
- yn <- rbind(y[,1:2],cbind(ex,NA))
- }else{yn <- y[,1:2]}
- yn <- yn[order(yn[,1]),]
- for(i in 2:dim(yn)[1]){
- if(is.na(yn[i,2])){
- yn[i,2] <- yn[(i-1),2]
- }
- }
- y <- createmsarray(yn,sa)
- d <- vector()
- for(i in 1:(dim(y)[1]-1)){
- z <- match(y[i+1,1],x[,1])-1
- d[i] <- x[z,4]-y[i,4]
- }
- round(d*1000,digits=3)
- }
- selectsol <- function(sol # if extreme= false this will select the best option out of all evaluated solutions
- ,og){ # number of bpms removed is the primary criterion
- solux <- cbind((dim(og)[1]-1) - (unlist(lapply(lapply(lapply(sol,"[[",1),dim),"[",1))-1),sqrt(cbind(unlist(lapply(lapply(lapply(sol,"[[",2),abs),mean,na.rm=TRUE)),unlist(lapply(lapply(lapply(sol,"[[",2),abs),max,na.rm=TRUE)))))
- rownames(solux) <- 1:dim(solux)[1]
- solux <- solux[which(solux[,2]<sqrt(mva) & solux[,3] < sqrt(mvs)),]
- solux <- cbind(solux[,1],rowSums(solux[,2:3]))
- solux <-as.numeric(names(which.min(solux[solux[,1]==tail(solux[order(solux[,1])],1),,drop=FALSE][,2])))
- }
- tolpass <- function(tol,mt,mva,mvs,ti
- ,og # original ms array used for variance checks/stops
- ,sol){ # solution list
- if(dim(og)[1]==2){return(list(og,0))}
- if(round(tol,digits=3)>=mt){
- if(extreme==FALSE){return(sol[[length(sol)]])
- }else{
- cat(paste("Extreme mode enabled... solution",selectsol(sol,og),"selected.","\n"))
- return(sol[[selectsol(sol,og)]])}}
- tol <- tol+ti
- e <- og[,1:2]
- oa <- multipass(tol,mva,mvs,e)
- msv <- msvar(og,oa)
- rbpm <- (dim(og)[1]-1)-(dim(oa)[1]-1)
- cat(paste("tol =",tol,"msva =",round(mean(msv),digits=3),"removed",rbpm,"of",(dim(og)[1]-1),"bpms","\n"))
- if(extreme==FALSE){
- if(length(which(abs(msv)>mvs))>0){
- if(length(sol)==0){
- cat(paste("Max variance average exceeded... returning original bpmline","\n"))
- return(list(og,0))}
- cat(paste("Max variance single exceeded... returning previous solution","\n"))
- return(sol[[length(sol)]])}
- if(mean(abs(msv))>mva){
- if(length(sol)==0){
- cat(paste("Max variance average exceeded... returning original bpmline","\n"))
- return(list(og,0))}
- cat(paste("Max variance average exceeded... returning previous solution","\n"))
- return(sol[[length(sol)]])}
- }
- sol[[length(sol)+1]] <- list(oa,msv)
- tolpass(tol,mt,mva,mvs,ti,og,sol)
- }
- multipass <- function(tol,mva,mvs
- ,e){ # reset bpm array from previous output
- o <- NULL
- o <- collapsebpm(tol,o,e,sa)
- oa <- createmsarray(o,sa,fb)
- msv <- msvar(og,oa)
- if(length(which(abs(msv)>mvs))>0){return(oa)}
- if(mean(abs(msv))>mva){return(oa)}
- if(dim(o)[1]>1){
- t <- cbind(o,c(0,o[1:(dim(o)-1)[1],2]))[1:(dim(o)[1]-1),,drop=FALSE]
- tt <- length(t[which(abs(t[,2]-t[,3])<0.5*tol),])
- }else{tt<-0}
- if(tt!=0){
- e <- oa[,1:2]
- }else{return(oa)}
- multipass(tol,mva,mvs,e)
- }
- collapsebpm <- function(tol
- ,o # new output bpm array
- ,e # extracted bpm array from each iteration
- ,sa){ # stop array
- p <- rep(c(e[1,2],e[2,2]),((dim(e)[1])/2))
- n <- suppressWarnings(head(which(p!=e[1:(dim(e)[1]-1),2]),1)-1)
- if(abs(p[1]-p[2])<=tol){
- if(length(n)==0){n<-dim(e)[1]}
- if(n==dim(e)[1]){
- n <- n-1
- if(e[n+1,1]-e[n,1]<=2){n<-n-1}
- }
- l <- createmsarray(e[1:n,],sa=NULL,fb=e[n+1,1])[n,4]
- bpm <- round((e[n+1,1]-e[1,1])/(l/60),digits=4)
- }else{
- bpm<-e[1,2]
- n<-1
- }
- o <- rbind(o,c(e[1,1],bpm))
- if(n==dim(e)[1]|is.vector(e[(n+1):dim(e)[1],])){return(o)}
- e <- e[(n+1):dim(e)[1],]
- collapsebpm(tol,o,e,sa)
- }
- rebuildline <- function(oa # array to rebuild
- ,x){ # data designation
- if(!is.null(oa)){
- a <- oa[1:dim(oa)[1]-1,1:2,drop=FALSE]
- a <- round(a,digits=4)
- n <- paste(a[,1],a[,2],sep="=")
- }else{
- n <- ""
- }
- paste(x,paste(n,collapse=","),";",sep="")
- }
- neg <- function(ba # check bpm and stop arrays for neg/0 values
- ,sa){
- n <- length(which(ba[,2]<=0))
- n2 <- length(which(sa[,2]<=0))
- sum(n,n2)
- }
- # Dump log data
- if(patch==TRUE){cat(paste("Flux capacitor initialized with the following parameters:","\n"
- ,"Max flux tolerance =",mt,"\n"
- ,"Max average ms variation threshold =",mva,"\n"
- ,"Max single ms variation threshold =",mvs,"\n"
- ,"Flux tolerance interval =",ti,"\n","\n"))
- cat(paste("Processing...",sdir,"\n"))}
- # Read and clean data
- options(expressions=25000)
- if(missing(sdir)){sdir <- getwd()}
- sm <- read.sm(sdir)
- if(is.null(sm)){
- cat(paste("No .sm found.","\n","\n","\n"))
- return(NULL)
- }
- fb <- getfb(sm)
- bpmline <- rowmerge(sm,"#BPMS:")
- stopline <- rowmerge(sm,"#STOPS:")
- sm <- rowremove(sm,x="#BPMS")
- sm <- rowremove(sm,x="#STOPS")
- ba <- createbpmarray(bpmline,fb)
- sa <- createstoparray(stopline,fb)
- og <- createmsarray(ba,sa)
- # Processing
- if(neg(ba,sa)==0){
- tol <- 0
- sol <- list()
- solux <- tolpass(tol,mt,mva,mvs,ti,og,sol)
- newbpms <- rebuildline(solux[[1]],x="#BPMS:")
- newstops <- rebuildline(sa,x="#STOPS:")
- if(patch==FALSE){
- o <- newbpms
- }else{
- sm[substr(sm,1,6)=="#BPMS:"] <- newbpms
- sm[substr(sm,1,7)=="#STOPS:"] <- newstops
- cat(paste("Original BPMline:",bpmline,"\n"))
- cat(paste("Output BPMline:",newbpms,"\n"))
- cat(paste("MS Variance:",paste(solux[[2]],collapse=","),"\n","\n","\n"))
- o <- sm
- }
- }else{
- if(patch==TRUE){
- o <- read.sm(sdir)
- }else{}
- cat(paste("Negative or 0 bpms/stops detected ","(",neg(ba,sa),")","\n",sep=""))
- cat(paste("No adjustments will be made to the .sm","\n","\n","\n"))
- }
- if(exists("o")){o}
- }
Add Comment
Please, Sign In to add comment