/*
* DecimatedWaveStake.java
* Eisenkraut
*
* Copyright (c) 2004-2016 Hanns Holger Rutz. All rights reserved.
*
* This software is published under the GNU General Public License v3+
*
*
* For further information, please contact Hanns Holger Rutz at
* contact@sciss.de
*/
package de.sciss.eisenkraut.io;
import java.io.IOException;
import de.sciss.io.InterleavedStreamFile;
import de.sciss.io.Span;
import de.sciss.timebased.BasicStake;
import de.sciss.timebased.Stake;
import de.sciss.util.MutableInt;
import de.sciss.util.MutableLong;
public class DecimatedStake extends BasicStake {
private final InterleavedStreamFile[] fs;
private final Span[] fileSpans;
private final Span[] maxFileSpans;
private final MutableLong[] framesWritten;
private final Span[] biasedSpans;
private final DecimationHelp[] decimations;
private final int SUBNUM;
public DecimatedStake(Span span, InterleavedStreamFile[] fs, Span[] fileSpans, Span[] biasedSpans,
DecimationHelp[] decimations) {
this(span, fs, fileSpans, fileSpans, null, biasedSpans, decimations);
}
private DecimatedStake( Span span, InterleavedStreamFile[] fs, Span[] fileSpans,
Span[] maxFileSpans, MutableLong[] framesWritten, Span[] biasedSpans,
DecimationHelp[] decimations )
{
super( span );
this.fs = fs;
this.fileSpans = fileSpans;
this.maxFileSpans = maxFileSpans;
if( framesWritten == null ) {
this.framesWritten = new MutableLong[ fs.length ];
for( int i = 0; i < fs.length; i++ ) this.framesWritten[ i ] = new MutableLong( 0L );
} else {
this.framesWritten = framesWritten;
}
this.biasedSpans = biasedSpans;
this.decimations = decimations;
SUBNUM = decimations.length;
}
public void dispose() {
// XXX
super.dispose();
}
public Stake duplicate()
{
return new DecimatedStake( span, fs, fileSpans, maxFileSpans, framesWritten, biasedSpans, decimations );
}
public Stake replaceStart( long newStart )
{
final Span[] newBiasedSpans = new Span[ SUBNUM ];
final Span[] newFileSpans = new Span[ SUBNUM ];
long testBias, newBiasedStart, delta;
DecimationHelp decim;
for( int i = 0; i < SUBNUM; i++ ) {
decim = decimations[ i ];
testBias = biasedSpans[ i ].start + ((newStart - span.start + decim.roundAdd) & decim.mask) - newStart;
newBiasedStart = newStart + (testBias < -decim.roundAdd ? testBias + decim.factor :
(testBias > decim.roundAdd ? testBias - decim.factor : testBias));
delta = (newBiasedStart - biasedSpans[ i ].start) >> decim.shift;
newBiasedSpans[ i ] = biasedSpans[ i ].replaceStart( newBiasedStart );
newFileSpans[ i ] = fileSpans[ i ].replaceStart( fileSpans[ i ].start + delta );
// XXX modify framesWritten ?
}
return new DecimatedStake( span.replaceStart( newStart ), fs, newFileSpans, maxFileSpans, framesWritten, newBiasedSpans, decimations );
}
public Stake replaceStop( long newStop )
{
final Span[] newBiasedSpans = new Span[ SUBNUM ];
final Span[] newFileSpans = new Span[ SUBNUM ];
long testBias, newBiasedStop; // , delta;
int startBias;
DecimationHelp decim;
for( int i = 0; i < SUBNUM; i++ ) {
decim = decimations[ i ];
startBias = (int) (biasedSpans[ i ].start - span.start);
testBias = (int) (((startBias + newStop + decim.roundAdd) & decim.mask) - newStop);
newBiasedStop = newStop + (testBias < -decim.roundAdd ? testBias + decim.factor :
(testBias > decim.roundAdd ? testBias - decim.factor : testBias));
newBiasedSpans[ i ] = biasedSpans[ i ].replaceStop( newBiasedStop );
newFileSpans[ i ] = fileSpans[ i ].replaceStop( fileSpans[ i ].start + newBiasedSpans[ i ].getLength() ); // XXX richtig?
}
return new DecimatedStake( span.replaceStop( newStop ), fs, newFileSpans, maxFileSpans, framesWritten, newBiasedSpans, decimations );
}
public Stake shiftVirtual( long delta )
{
final Span[] newBiasedSpans = new Span[ SUBNUM ];
for( int i = 0; i < SUBNUM; i++ ) {
newBiasedSpans[ i ] = biasedSpans[ i ].shift( delta );
}
return new DecimatedStake( span.shift( delta ), fs, fileSpans, maxFileSpans, framesWritten, newBiasedSpans, decimations );
}
public void readFrames( int sub, float[][] data, int dataOffset, Span readSpan, MutableInt framesRead, MutableInt framesBusy )
throws IOException
{
if( data.length == 0 ) {
framesRead.set( 0 );
framesBusy.set( 0 );
return;
}
final DecimationHelp decim = decimations[ sub ];
final int startBias = (int) (biasedSpans[ sub ].start - span.start);
final int newStartBias = (int) (((readSpan.start + decim.roundAdd) & decim.mask) - readSpan.start) + startBias;
final long newBiasedStart = readSpan.start + (newStartBias < -decim.roundAdd ? newStartBias + decim.factor :
(newStartBias > decim.roundAdd ? newStartBias - decim.factor : newStartBias));
final long fOffset = fileSpans[ sub ].start + ((newBiasedStart - (span.start + startBias)) >> decim.shift);
final int newStopBias = (int) (((startBias + readSpan.stop + decim.roundAdd) & decim.mask) - readSpan.stop);
final long newBiasedStop = readSpan.stop + (newStopBias < -decim.roundAdd ? newStopBias + decim.factor :
(newStopBias > decim.roundAdd ? newStopBias - decim.factor : newStopBias));
final int len = (int) Math.min( data[0].length - dataOffset, (newBiasedStop - newBiasedStart) >> decim.shift );
final int readyLen;
if( len <= 0 ) {
framesRead.set( 0 );
framesBusy.set( 0 );
return;
}
synchronized( fs ) {
readyLen = (int) Math.min( len, Math.max( 0, fileSpans[ sub ].start + framesWritten[ sub ].value() - fOffset ));
if( readyLen > 0 ) {
if( fs[ sub ].getFramePosition() != fOffset ) {
fs[ sub ].seekFrame( fOffset );
}
// XXX TEST
// fs[ sub ].readFrames( data, dataOffset, len );
// readyLen = (int) Math.min( len, framesWritten[ sub ].value() - fOffset );
fs[ sub ].readFrames( data, dataOffset, readyLen );
}
}
framesRead.set( readyLen );
framesBusy.set( len - readyLen );
}
public boolean readFrame(int sub, float[][] data, int dataOffset, long pos)
throws IOException {
final DecimationHelp decim = decimations[ sub ];
final int startBias = (int) (biasedSpans[ sub ].start - span.start);
final int newStartBias = (int) (((pos + decim.roundAdd) & decim.mask) - pos) + startBias;
final long newBiasedStart = pos + (newStartBias < -decim.roundAdd ? newStartBias + decim.factor :
(newStartBias > decim.roundAdd ? newStartBias - decim.factor : newStartBias));
final long fOffset = fileSpans[ sub ].start + ((newBiasedStart - (span.start + startBias)) >> decim.shift);
final int readyLen;
synchronized( fs ) {
readyLen = (int) Math.min( 1, fileSpans[ sub ].start + framesWritten[ sub ].value() - fOffset );
if( readyLen == 1 ) {
if( fs[ sub ].getFramePosition() != fOffset ) {
fs[ sub ].seekFrame( fOffset );
}
fs[ sub ].readFrames( data, dataOffset, 1 );
return true;
} else {
return false;
}
}
}
public void continueWrite(int sub, float[][] data, int dataOffset, int len)
throws IOException {
if (len == 0) return; // return 0;
synchronized (fs) {
final long fOffset = fileSpans[sub].start + framesWritten[sub].value();
if( (fOffset < fileSpans[ sub ].start) || ((fOffset + len) > fileSpans[ sub ].stop) ) {
throw new IllegalArgumentException( fOffset + " ... " + (fOffset + len) + " not within " + fileSpans[ sub ].toString() );
}
if( fs[ sub ].getFramePosition() != fOffset ) {
fs[ sub ].seekFrame( fOffset );
}
fs[ sub ].writeFrames( data, dataOffset, len );
framesWritten[ sub ].add( len );
}
}
public void flush()
throws IOException {
synchronized (fs) {
for (InterleavedStreamFile f : fs) {
f.flush();
}
}
}
public void debugDump()
{
debugDumpBasics();
for( int i = 0; i < SUBNUM; i++ ) {
System.err.println( " decim "+decimations[i].factor+" biased span "+biasedSpans[i].toString()+
"; f = " + fs[i].getFile().getName() + " (file span " + fileSpans[i].toString() + " )" );
}
}
protected void debugDumpBasics()
{
System.err.println( "Span " + span.toString() );
}
}