package de.maramuse.soundcomp.test;
/*
* Copyright 2011 Jan Schmidt-Reinisch
*
* SoundComp - a sound processing library
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; in version 2.1
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* Test cases for timing calculations
*/
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import de.maramuse.soundcomp.control.Control;
import de.maramuse.soundcomp.events.ExponentialTempoChangeEvent;
import de.maramuse.soundcomp.events.HarmonicTempoChangeEvent;
import de.maramuse.soundcomp.events.InverseTempoChangeEvent;
import de.maramuse.soundcomp.events.LinearTempoChangeEvent;
import de.maramuse.soundcomp.events.SeamlessTempoChangeEvent;
import de.maramuse.soundcomp.events.TempoChangeEvent;
import de.maramuse.soundcomp.parser.Parser;
import de.maramuse.soundcomp.parser.Preprocessor;
import de.maramuse.soundcomp.parser.SCParser;
import de.maramuse.soundcomp.parser.SoundCompText;
import de.maramuse.soundcomp.parser.SCParser.ParserVal;
import junit.framework.TestCase;
public class TimingTests extends TestCase {
/**
* code to verify the timeline creation
*/
public void testTimeline() throws Exception {
Parser parser=new Parser();
parser.setDebug(false);
parser.setOptimize(true);
List<String> paths=new ArrayList<String>();
File file=new File("javasrc/de/maramuse/soundcomp/test/testfiles/tempotest");
Preprocessor.setDebug(false);
ParserVal p=parser.parse(file, paths);
if(p==null){
SCParser.ParserVal val=parser.getLastSymbol();
if(val==null){
fail("no result and no error text");
return;
}
String filename=val.getFilename();
if(filename==null)
filename="direct input";
parser.dumpStack();
fail(String.format("%s after reading %s(%s), %s, %d",
parser.getError(),
parser.getSymbol(val.getType()), val.getText(),
val.getFilename(),
val.getLine()));
}
if(!(p instanceof SoundCompText))
fail("Parsing didn't create a SoundCompText object");
SoundCompText sct=(SoundCompText)p;
new Control(sct).execute();
}
/**
* code to verify the tempo change event calculations - as these are far from
* being trivial, we must test all of them for plausible calculation results.
*/
public void testTempoChangeCalculations() {
TempoChangeEvent itce=new InverseTempoChangeEvent(10d);
itce.setBeat(0);
TempoChangeEvent etce=new ExponentialTempoChangeEvent(10d);
etce.setBeat(0);
TempoChangeEvent stce=new SeamlessTempoChangeEvent(10d);
stce.setBeat(0);
TempoChangeEvent htce=new HarmonicTempoChangeEvent(10d);
htce.setBeat(0);
TempoChangeEvent ltce=new LinearTempoChangeEvent(10d);
ltce.setBeat(0);
System.out.println("testing inverse tc accel");
testTempoChange(itce, true);
System.out.println("testing exponential tc accel");
testTempoChange(etce, true);
System.out.println("testing harmonic tc accel");
testTempoChange(htce, true);
System.out.println("testing seamless tc accel");
testTempoChange(stce, true);
System.out.println("testing linear tc accel");
testTempoChange(ltce, true);
itce=new InverseTempoChangeEvent(10d);
itce.setBeat(0);
etce=new ExponentialTempoChangeEvent(10d);
etce.setBeat(0);
stce=new SeamlessTempoChangeEvent(10d);
stce.setBeat(0);
htce=new HarmonicTempoChangeEvent(10d);
htce.setBeat(0);
System.out.println("testing inverse tc decel");
testTempoChange(itce, false);
System.out.println("testing exponential tc decel");
testTempoChange(etce, false);
System.out.println("testing harmonic tc decel");
testTempoChange(htce, false);
System.out.println("testing seamless tc decel");
testTempoChange(stce, false);
System.out.println("testing linear tc decel");
testTempoChange(ltce, false);
}
private void testTempoChange(TempoChangeEvent ctce, boolean accel){
ctce.setBeats(5);
if(accel){
ctce.setStartBpm(50);
ctce.setEndBpm(70);
}else{
ctce.setStartBpm(70);
ctce.setEndBpm(50);
}
ctce.init();
double res=ctce.calculateRelativeBeatTime(0);
if(res>=0.00001d)fail();
if(res<=-0.00001d)
fail();
if(Double.isNaN(res)||Double.isInfinite(res))
fail();
testTempoChangeInternal1(ctce, 0, 1);
testTempoChangeInternal1(ctce, 1, 2);
testTempoChangeInternal1(ctce, 2, 3);
testTempoChangeInternal1(ctce, 3, 4);
testTempoChangeInternal1(ctce, 4, 5);
testTempoChangeInternal2(ctce, 10);
testTempoChangeInternal2(ctce, 11);
testTempoChangeInternal2(ctce, 12);
testTempoChangeInternal2(ctce, 13);
testTempoChangeInternal2(ctce, 14);
testTempoChangeInternal2(ctce, 15);
testTempoChangeInternal3(ctce, 10);
testTempoChangeInternal3(ctce, 11);
testTempoChangeInternal3(ctce, 12);
testTempoChangeInternal3(ctce, 13);
testTempoChangeInternal3(ctce, 14);
testTempoChangeInternal3(ctce, 15);
testTempoChangeInternal4(ctce, 0);
testTempoChangeInternal4(ctce, 1);
testTempoChangeInternal4(ctce, 2);
testTempoChangeInternal4(ctce, 3);
testTempoChangeInternal4(ctce, 4);
testTempoChangeInternal4(ctce, 5);
}
private void testTempoChangeInternal1(TempoChangeEvent ctce, double beat1, double beat2){
double bt1=ctce.calculateRelativeBeatTime(beat1);
if(Double.isNaN(bt1)||Double.isInfinite(bt1))
fail();
double bt2=ctce.calculateRelativeBeatTime(beat2);
if(Double.isNaN(bt2)||Double.isInfinite(bt2))
fail();
System.out.println("time at beat "+beat2+" is "+bt2);
}
private void testTempoChangeInternal2(TempoChangeEvent ctce, double timestamp){
double beats=ctce.getBeats();
double end=ctce.calculateRelativeBeatTime(beats)+ctce.getTimestamp();
if(timestamp>end)return;
double bt1=ctce.calculateBeatFromTimestamp(timestamp);
if(Double.isNaN(bt1)||Double.isInfinite(bt1))
fail();
System.out.println("beat at time "+timestamp+" is "+bt1);
}
private void testTempoChangeInternal3(TempoChangeEvent ctce, double timestamp){
double beats=ctce.getBeats();
double end=ctce.calculateRelativeBeatTime(beats)+ctce.getTimestamp();
if(timestamp>end)return;
double tp1=ctce.calculateTempoFromTimestamp(timestamp);
if(Double.isNaN(tp1)||Double.isInfinite(tp1))
fail();
System.out.println("tempo at time "+timestamp+" is "+tp1*60);
}
private void testTempoChangeInternal4(TempoChangeEvent ctce, double beat){
double beats=ctce.getBeats();
if(beat>beats)return;
double tp1=ctce.calculateTempoFromBeat(beat);
if(Double.isNaN(tp1)||Double.isInfinite(tp1))
fail();
System.out.println("tempo at beat "+beat+" is "+tp1*60);
}
}