final Application app = AbstractApplication.getApplication();
float[][] inTrnsFrames, outTrnsFrames;
int minBlockSize, maxBlockSize, prefBlockSize;
int i, numTrns, numRcv, trnsIdx, rcvIdx, readLen, writeLen;
Transmitter trns;
AudioTrail at;
boolean[] trnsRequest;
Object val;
long readOffset, remainingRead, remainingWrite;
Set newOptions;
String className;
boolean success = false; // pessimist bitchâ„¢
// --- resampling related ---
int inOff, inTrnsLen, outTrnsLen;
int fltLenI = 0;
int overlapLen = 0;
int overlapOff = 0;
int trnsInside = 0;
Resampling rsmp = null;
double rsmpFactor = 1.0;
double inPhase = 0.0;
double newInPhase = 0.0;
double fltLen = 0.0;
float[][][] trnsOverlaps= null;
// --- init ---
readOffset = context.getTimeSpan().getStart();
numRcv = context.getReceivers().size();
numTrns = context.getTransmitters().size();
source = new RenderSource( numTrns, numRcv );
try {
if( !invokeProducerBegin( pt, context, source, plugIn )) return FAILED;
remainingRead = context.getTimeSpan().getLength();
newOptions = context.getModifiedOptions();
if( newOptions.contains( RenderContext.KEY_MINBLOCKSIZE )) {
val = context.getOption( RenderContext.KEY_MINBLOCKSIZE );
minBlockSize = ((Integer) val).intValue();
} else {
minBlockSize = 1;
}
if( newOptions.contains( RenderContext.KEY_MAXBLOCKSIZE )) {
val = context.getOption( RenderContext.KEY_MAXBLOCKSIZE );
maxBlockSize = ((Integer) val).intValue();
} else {
maxBlockSize = 0x7FFFFF;
}
if( newOptions.contains( RenderContext.KEY_PREFBLOCKSIZE )) {
val = context.getOption( RenderContext.KEY_PREFBLOCKSIZE );
prefBlockSize = ((Integer) val).intValue();
} else {
prefBlockSize = Math.max( minBlockSize, Math.min( maxBlockSize, 1024 ));
}
assert minBlockSize <= maxBlockSize : "minmaxblocksize";
if( newOptions.contains( RenderContext.KEY_TARGETRATE )) {
// ---- prepare resampling ----
val = context.getOption( RenderContext.KEY_TARGETRATE );
rsmpFactor = ((Double) val).doubleValue() / (double) context.getSourceRate();
className = classPrefs.get( KEY_RESAMPLING, null );
if( className == null ) {
className = NearestNeighbour.class.getName(); // RSMP_ITEMS[ 0 ].getKey();
showMessage( JOptionPane.WARNING_MESSAGE, app.getResourceString( "errResamplingClass" ) +
" : " + val.toString() );
}
try {
rsmp = (Resampling) Class.forName( className ).newInstance();
}
catch( InstantiationException e1 ) {
pt.setException( e1 );
return FAILED;
}
catch( IllegalAccessException e2 ) {
pt.setException( e2 );
return FAILED;
}
catch( ClassNotFoundException e3 ) {
pt.setException( e3 );
return FAILED;
}
finally {
if( rsmp == null ) {
showMessage( JOptionPane.ERROR_MESSAGE,
app.getResourceString( "errResamplingClass" ) + " : " + className );
}
}
fltLen = rsmp.getWingSize( rsmpFactor );
fltLenI = (int) fltLen + 1;
inOff = fltLenI;
overlapLen = fltLenI << 1;
if( rsmpFactor > 1.0 ) {
outTrnsLen = prefBlockSize;
i = (int) (outTrnsLen / rsmpFactor);
inTrnsLen = i + overlapLen;
} else {
inTrnsLen = Math.max( prefBlockSize, fltLenI + overlapLen );
i = inTrnsLen - overlapLen;
outTrnsLen = (int) (i * rsmpFactor) + 1;
}
overlapOff = inTrnsLen - overlapLen;
trnsInside = inTrnsLen - fltLenI - fltLenI;
trnsOverlaps = new float[ numTrns ][2][ overlapLen ];
inTrnsFrames = new float[2][ inTrnsLen ];
outTrnsFrames = new float[2][ outTrnsLen ];
remainingWrite = (long) (remainingRead * rsmpFactor + 0.5);
//System.err.println( "fltLen "+fltLen+"; inOff "+inOff+"; overlapLen "+overlapLen+"; inTrnsLen "+inTrnsLen+"; outTrnsLen "+outTrnsLen+"; rsmpFactor "+rsmpFactor );
} else {
inTrnsLen = prefBlockSize;
outTrnsLen = inTrnsLen;
inTrnsFrames = new float[2][ inTrnsLen ];
outTrnsFrames = inTrnsFrames;
inOff = 0;
remainingWrite = remainingRead;
}
// --- responding to RenderSource requests ---
trnsRequest = new boolean[ numTrns ]; // all false by default
for( trnsIdx = 0; trnsIdx < numTrns; trnsIdx++ ) {
if( source.trajRequest[ trnsIdx ]) {
source.trajBlockBuf[ trnsIdx ] = new float[ 2 ][ outTrnsLen ];
trnsRequest[ trnsIdx ] = true;
}
for( rcvIdx = 0; rcvIdx < numRcv; rcvIdx++ ) {
if( source.senseRequest[ trnsIdx ][ rcvIdx ]) {
source.senseBlockBuf[ trnsIdx ][ rcvIdx ] = new float[ outTrnsLen ];
trnsRequest[ trnsIdx ] = true;
}
}
}
// --- rendering loop ---
while( isRunning() && remainingWrite > 0 ) {
readLen = (int) Math.min( inTrnsLen - inOff, remainingRead );
source.blockSpan = new Span( readOffset, readOffset + readLen );
if( rsmp != null ) {
inPhase = newInPhase;
writeLen = (int) Math.min( Math.ceil( (trnsInside - inPhase) * rsmpFactor ), remainingWrite );
} else {
writeLen = readLen;
}
source.blockBufLen = writeLen;
for( trnsIdx = 0; trnsIdx < numTrns; trnsIdx++ ) {
if( !trnsRequest[ trnsIdx ]) continue;
// --- read transmitter trajectory data ---
trns = (Transmitter) context.getTransmitters().get( trnsIdx );
at = trns.getAudioTrail();
// at.read( source.blockSpan, inTrnsFrames, inOff );
at.readFrames( inTrnsFrames, inOff, source.blockSpan );
for( i = inOff + readLen; i < inTrnsLen; i++ ) {
inTrnsFrames[0][i] = 0.0f; // zero pad in the end
inTrnsFrames[1][i] = 0.0f; // XXX actually the last sample should be repeated!