import java.io.*;
import java.awt.*;
import jass.render.*;
import jass.engine.*;
import jass.generators.*;
/**
Render to raw 16 bit PCM file (or ascii) tmp.raw as long as not interrupted or to real-time audio
*/
public class HailDemo extends Thread {
public static void main(String[] args)
throws InterruptedException, SinkIsFullException, FileNotFoundException {
int bufferSize = 1024;
int bufferSizeJavaSound = 1024*16;
int nFramesToSkip = 2;
float srate = 22050;
int twait = 50;
boolean ascii = false;
boolean toFile = false;
final int nObjects = 9;
int nf=10000; // set to 10000 to do all modes
// int np=1;
//float fmin=100,fmax=6000,mmcmin=.001f,mmcmax=.002f,amin=0,amax=1;
float probExponent0 = 10;
float eventDensity0 = .0001f;
// renderer
final SourcePlayer sp1;
if(toFile) {
sp1 = new SourcePlayer(bufferSize,srate,"tmp.raw");
} else {
sp1 = new SourcePlayer(bufferSize,bufferSizeJavaSound,srate);
}
// sources
final RandPulses[] af = new RandPulses[nObjects];
for(int i=0;i<nObjects;i++) {
af[i] = new RandPulses(bufferSize);
}
final ModalModel[] mm = new ModalModel[nObjects];
// volumes for all objects, depends on point of listening, set to defaults
float[] ascale = new float[]{1,1,1,1,1,1,1,1,1};
mm[0] = new ModalModel("../data/rectplate1.2_1.14.syenSortp_5.sy");
mm[1] = new ModalModel("../data/rectplate1.4_1.14.syenSortp_5.sy");
mm[2] = new ModalModel("../data/rectplate2_1.14.syenSortp_5.sy");
mm[3] = new ModalModel("../data/rectplate3_1.14.syenSortp_5.sy");
mm[4] = new ModalModel("../data/metalobject1.syenSortp_5.sy");
mm[5] = new ModalModel("../data/metalobject2.syenSortp_5.sy");
mm[6] = new ModalModel("../data/metalobject3.syenSortp_5.sy");
mm[7] = new ModalModel("../data/woodentable1.syenSortp_5.sy");
mm[8] = new ModalModel("../data/timecapsule.syensortp_5.sy");
/*
for(int i=0;i<nObjects;i++) {
mm[i] = new RandomModalModel(
200,1,50f,10000f,.001f,.01f,.0001f,1f);
}
*/
for(int i=0;i<nObjects;i++) {
mm[i].ascale = ascale[i];
}
final QuenchableModalObjectWithOneContact[] mo = new QuenchableModalObjectWithOneContact[nObjects];
for(int i=0;i<nObjects;i++) {
mo[i] = new QuenchableModalObjectWithOneContact(mm[i],srate,bufferSize);
}
final ModalQuencher modalQuencher = new ModalQuencher(bufferSize,nFramesToSkip);
modalQuencher.setFramesToSkip(nFramesToSkip);
// add modal objects to quencher
for(int i=0;i<nObjects;i++) {
modalQuencher.addModalObject(mo[i]);
}
// connect sources to quencher
for(int i=0;i<nObjects;i++) {
modalQuencher.addSource(af[i]);
}
// initialize quencher; an add no more sources or modalObjects now
modalQuencher.init();
// connect sources to objects
for(int i=0;i<nObjects;i++) {
mo[i].addSource(af[i]);
}
// connect objects to renderer, quencher first
sp1.addSource(modalQuencher);
for(int i=0;i<nObjects;i++) {
sp1.addSource(mo[i]);
}
// Begin control panel code
boolean isModal = false;
final int nNonGainSliders = 5;
int nsliders = nNonGainSliders+nObjects;
int nbuttons = 4;
Controller a_controlPanel = new Controller(new java.awt.Frame ("Hail"),
isModal,nsliders,nbuttons) {
public void onButton(int k) {
switch(k) {
case 0:
sp1.resetAGC();
modalQuencher.resetLevel();
break;
case 1: {
FileDialog fd = new FileDialog(new Frame(),"Save");
fd.setMode(FileDialog.SAVE);
fd.setVisible(true);
saveToFile(fd.getFile());
}
break;
case 2: {
FileDialog fd = new FileDialog(new Frame(),"Load");
fd.setMode(FileDialog.LOAD);
fd.setVisible(true);
loadFromFile(fd.getFile());
applySliders();
break;
}
case 3:
int nKilled = modalQuencher.getNKilledModes();
int totalModes = modalQuencher.getTotalModes();
System.out.println("killed = "+nKilled +" remaining = "+ (totalModes-nKilled)+" out of "+totalModes);
break;
}
}
private void applySliders() {
for(int i=0;i<this.nsliders;i++) {
onSlider(i);
}
}
public void onSlider(int k) {
switch(k) {
case 0:
for(int i=0;i<nObjects;i++) {
af[i].setProbabilityPerSample((float)super.val[0]);
}
break;
case 1:
for(int i=0;i<nObjects;i++) {
af[i].setProbabilityDistributionExponent((float)super.val[1]);
}
break;
case 2:
int nfToUse = (int)super.val[2];
if(nfToUse < 10000) {
for(int i=0;i<nObjects;i++) {
if(mm[i].nf > nfToUse) {
mm[i].nfUsed = nfToUse;
}
}
}
break;
case 3:
float dbLevel = (float)super.val[3];
modalQuencher.setDbLevelLoudestMode(dbLevel);
break;
case 4:
float av = (float)super.val[4];
modalQuencher.setAv(av);
break;
default:
int objNumber = k-nNonGainSliders;
mo[objNumber].setGain((float)super.val[k]);
break;
}
}
};
// names, values, and ranges of sliders
String[] names = {"HailDensity ",
"MassDistributionExponent ",
"#modes ",
"dB level ",
"maskThreshold ",
"gain0 ",
"gain1 ",
"gain2 ",
"gain3 ",
"gain4 ",
"gain5 ",
"gain6 ",
"gain7 ",
"gain8 "
};
double[] val = {eventDensity0,
probExponent0,
nf,
60,
20,
1,
1,
1,
1,
1,
1,
1,
1,
1
};
double[] min = {0,
0,
1,
10,
0,
0.00001,
0.00001,
0.00001,
0.00001,
0.00001,
0.00001,
0.00001,
0.00001,
0.00001
};
double[] max = {.1,
1000,
10000,
140,
100,
1,
1,
1,
1,
1,
1,
1,
1,
1
};
a_controlPanel.setSliders(val,min,max,names);
a_controlPanel.setButtonNames(new String[] {"Reset","Save","Load","Debug"});
a_controlPanel.setVisible(true);
for(int i=0;i<nsliders;i++) {
a_controlPanel.onSlider(i);
}
// End control panel code
long lt = 0;
float v=1;
if(toFile) {
try {
while(true) {
lt += twait;
double realTime = lt/1000.;
if(ascii) {
sp1.advanceTime(realTime,ascii);
} else {
sp1.advanceTime(realTime);
}
sleep(twait);
}
} catch(Exception e) {
System.out.println("RenderToFile"+e);
}
} else {
sp1.run();
}
}
}