Package de.sciss.eisenkraut.io

Source Code of de.sciss.eisenkraut.io.DecimatedTrail$AsyncEvent

/*
*  DecimatedTrail.java
*  Eisenkraut
*
*  Copyright (c) 2004-2014 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
*
*
*  Changelog:
*    15-Apr-08  extracted back from DecimatedWaveTrail
*/

package de.sciss.eisenkraut.io;

import java.awt.Paint;
import java.awt.Rectangle;
import java.awt.TexturePaint;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.swing.undo.CompoundEdit;

import de.sciss.app.BasicEvent;
import de.sciss.app.EventManager;
import de.sciss.common.ProcessingThread;
import de.sciss.eisenkraut.math.MathUtil;
import de.sciss.io.AudioFile;
import de.sciss.io.AudioFileDescr;
import de.sciss.io.IOUtil;
import de.sciss.io.Span;
import de.sciss.timebased.BasicTrail;

/**
@version  0.70, 15-Apr-08
@author    Hanns Holger Rutz
*/
public abstract class DecimatedTrail
extends BasicTrail
{
  protected static final boolean  DEBUG          = false;

  protected int          SUBNUM;
  protected int          MAXSHIFT;
  protected int          MAXCOARSE;
  protected long          MAXMASK;
  protected int          MAXCEILADD;

  public static final int      MODEL_PCM        = 0;
  public static final int      MODEL_HALFWAVE_PEAKRMS  = 1;
  public static final int      MODEL_MEDIAN      = 2;
  public static final int      MODEL_FULLWAVE_PEAKRMS  = 3;
  public static final int      MODEL_SONA        = 10;

  protected int          modelChannels;
  protected int          decimChannels;
  protected int          fullChannels;
  protected int          model;
 
  protected AudioFile[]      tempF          = null; // lazy
  protected DecimationHelp[]    decimHelps;
  protected AudioTrail      fullScale;

  protected float[][]        tmpBuf          = null; // lazy
  protected int          tmpBufSize;
  protected float[][]        tmpBuf2          = null; // lazy
  protected int          tmpBufSize2;

  // private static final Paint pntArea = new Color( 0x00, 0x00, 0x00, 0x7F );
  // private static final Paint pntNull = new Color( 0x7F, 0x7F, 0x00, 0xC0 );
  // private static final Stroke strkNull = new BasicStroke( 1.0f,
  // BasicStroke.CAP_SQUARE, BasicStroke.JOIN_BEVEL,
  // 1.0f, new float[] { 4.0f, 4.0f }, 0.0f );
  protected static final Paint  pntBusy;

  private static final int[]    busyPixels = {
      0xFFCBCBCB, 0xFFC0C0C0, 0xFFA8A8A8,
      0xFFE6E6E6, 0xFFB2B2B2, 0xFFCACACA,
      0xFFB1B1B1, 0xFFD5D5D5, 0xFFC0C0C0 };

  protected final Object      bufSync          = new Object();
  protected final Object      fileSync        = new Object();

  protected final List      drawBusyList      = new ArrayList();

  protected Thread        threadAsync        = null;
  protected AudioFile[]      tempFAsync        = null; // lazy
  protected volatile boolean    keepAsyncRunning    = false;

  protected EventManager      asyncManager      = null;
 
  protected static final double  TWENTYBYLOG10      = 20 / MathUtil.LN10; // 8.685889638065;
  protected static final double  TENBYLOG10        = 10 / MathUtil.LN10;

  static {
    final BufferedImage img = new BufferedImage( 3, 3, BufferedImage.TYPE_INT_ARGB );
    img.setRGB( 0, 0, 3, 3, busyPixels, 0, 3 );
    pntBusy = new TexturePaint( img, new Rectangle( 0, 0, 3, 3 ));
  }

  protected DecimatedTrail()
  {
    super();
  }

  protected BasicTrail createEmptyCopy()
  {
    throw new IllegalStateException( "Not allowed" );
  }

  public final int getDefaultTouchMode() { return TOUCH_SPLIT; }
  public final int getChannelNum() { return decimChannels; }
  public final int getNumModelChannels() { return modelChannels; }
  public final int getNumDecimations() { return SUBNUM; }
  public final int getModel() { return model; }

  public abstract DecimationInfo getBestSubsample( Span tag, int minLen );

  protected static void setProgression( long len, double progWeight )
  throws ProcessingThread.CancelledException
  {
    ProcessingThread.update( (float) (len * progWeight) );
  }

  protected static void flushProgression()
  {
    ProcessingThread.flushProgression();
  }

  protected final void killAsyncThread()
  {
    if( threadAsync != null ) {
      synchronized( threadAsync ) {
        if( threadAsync.isAlive() ) {
          keepAsyncRunning = false;
          try {
            threadAsync.wait();
          } catch( InterruptedException e1 ) {
            System.err.println( e1 );
          }
        }
      }
    }
  }

  protected void removeAllDep( Object source, List stakes, CompoundEdit ce, Span union )
  {
    if( DEBUG ) System.err.println( "removeAllDep " + union.toString() );
    if( 1 == 1 ) throw new IllegalArgumentException( "n.y.i." );

    // // ____ dep ____
    // if( dependants != null ) {
    //   synchronized( dependants ) {
    //     for( int i = 0; i < dependants.size(); i++ ) {
    //       ((Trail) dependants.get( i )).removeAllDep( source, stakes, ce, union
    //       );
    //     }
    //   }
    // }
  }

  protected abstract File[] createCacheFileNames();
 
  protected int[][] createCacheChannelMaps()
  {
    final int[][] fullChanMaps  = fullScale.getChannelMaps();
    final int[][] cacheChanMaps  = new int[ fullChanMaps.length ][];

    for( int i = 0; i < fullChanMaps.length; i++ ) {
//      System.out.println( "fullChanMaps[ " + i + " ] = " );
//      for( int k = 0; k < fullChanMaps[ i ].length; k++ ) {
//        System.out.println( "  " + fullChanMaps[ i ][ k ]);
//      }
      cacheChanMaps[ i ] = new int[ fullChanMaps[ i ].length * modelChannels ];
      for( int j = 0; j < cacheChanMaps[ i ].length; j++ ) {
        cacheChanMaps[ i ][ j ] = j;
      }
//      System.out.println( "cacheChanMaps[ " + i + " ] = " );
//      for( int k = 0; k < cacheChanMaps[ i ].length; k++ ) {
//        System.out.println( "  " + cacheChanMaps[ i ][ k ]);
//      }
    }

    return cacheChanMaps;
  }

  // @synchronization caller must have sync on fileSync !!!
  protected DecimatedStake alloc( Span span )
  throws IOException
  {
    if( !Thread.holdsLock( fileSync ) ) throw new IllegalMonitorStateException();

    final long floorStart = span.start & MAXMASK;
    final long ceilStop = (span.stop + MAXCEILADD) & MAXMASK;
    final Span extSpan = (floorStart == span.start) && (ceilStop == span.stop) ? span : new Span( floorStart,
    ceilStop );
    final Span[] fileSpans = new Span[ SUBNUM ];
    final Span[] biasedSpans = new Span[ SUBNUM ];
    long fileStart;
    long fileStop;

    if( tempF == null ) {
      tempF = createTempFiles(); // XXX sync
    }
    synchronized( tempF ) {
      for( int i = 0; i < SUBNUM; i++ ) {
        fileStart = tempF[ i ].getFrameNum();
        fileStop = fileStart + (extSpan.getLength() >> decimHelps[ i ].shift);
        tempF[ i ].setFrameNum( fileStop );
        fileSpans[ i ] = new Span( fileStart, fileStop );
        biasedSpans[ i ] = extSpan;
      }
    }
    return new DecimatedStake( extSpan, tempF, fileSpans, biasedSpans, decimHelps );
  }

  // @synchronization caller must have sync on fileSync !!!
  protected DecimatedStake allocAsync( Span span )
  throws IOException
  {
    if( !Thread.holdsLock( fileSync )) throw new IllegalMonitorStateException();

    final long floorStart  = span.start & MAXMASK;
    final long ceilStop    = (span.stop + MAXCEILADD) & MAXMASK;
    final Span extSpan    = (floorStart == span.start) && (ceilStop == span.stop) ?
                  span : new Span( floorStart, ceilStop );
    final Span[] fileSpans  = new Span[ SUBNUM ];
    final Span[] biasedSpans = new Span[ SUBNUM ];
    long fileStart;
    long fileStop;

    if( tempFAsync == null ) {
      // XXX THIS IS THE PLACE TO OPEN WAVEFORM CACHE FILE
      tempFAsync = createTempFiles();
    }
    synchronized( tempFAsync ) {
      for( int i = 0; i < SUBNUM; i++ ) {
        fileStart    = tempFAsync[ i ].getFrameNum();
        fileStop    = fileStart + (extSpan.getLength() >> decimHelps[ i ].shift);
        tempFAsync[ i ].setFrameNum( fileStop );
        fileSpans[ i = new Span( fileStart, fileStop );
        biasedSpans[ i ] = extSpan;
      }
    }
    return new DecimatedStake( extSpan, tempFAsync, fileSpans, biasedSpans, decimHelps );
  }

  protected AudioFile[] createTempFiles()
  throws IOException
  {
    // simply use an AIFC file with float format as temp file
    final AudioFileDescr proto  = new AudioFileDescr();
    final AudioFile[] tempFiles  = new AudioFile[ SUBNUM ];
    AudioFileDescr afd;
    proto.type          = AudioFileDescr.TYPE_AIFF;
    proto.channels        = decimChannels;
    proto.bitsPerSample      = 32;
    proto.sampleFormat      = AudioFileDescr.FORMAT_FLOAT;
    // proto.bitsPerSample = 8;
    // proto.sampleFormat = AudioFileDescr.FORMAT_INT;
    try {
      for( int i = 0; i < SUBNUM; i++ ) {
        afd        = new AudioFileDescr( proto );
        afd.file    = IOUtil.createTempFile();
        afd.rate    = decimHelps[ i ].rate;
        tempFiles[ i = AudioFile.openAsWrite( afd );
      }
      return tempFiles;
    } catch( IOException e1 ) {
      for( int i = 0; i < SUBNUM; i++ ) {
        if( tempFiles[ i ] != null ) tempFiles[ i ].cleanUp();
      }
      throw e1;
    }
  }

  protected void deleteTempFiles( AudioFile[] tempFiles )
  {
    for( int i = 0; i < tempFiles.length; i++ ) {
      if( tempFiles[ i ] != null ) {
        tempFiles[ i ].cleanUp();
        tempFiles[ i ].getFile().delete();
      }
    }
  }
 
  protected void freeTempFiles()
  {
    synchronized( fileSync ) {
      if( tempF != null ) {
        deleteTempFiles( tempF );
      }
      // XXX THIS IS THE PLACE TO KEEP WAVEFORM CACHE FILE
      if( tempFAsync != null ) {
        deleteTempFiles( tempFAsync );
      }
    }
  }

  /*
   * @synchronization call within synchronoized( bufSync ) block
   */
  protected void createBuffers()
  {
    if( !Thread.holdsLock( bufSync )) throw new IllegalMonitorStateException();

    if( tmpBuf == null ) {
     
//System.out.println( "tmpBuf  : [ " + fullChannels + " ][ " + tmpBufSize + " ]" );
//System.out.println( "tmpBuf2 : [ " + decimChannels + " ][ " + tmpBufSize2 + " ]" );
     
      tmpBuf  = new float[ fullChannels  ][ tmpBufSize ];
      tmpBuf2  = new float[ decimChannels ][ tmpBufSize2 ];
    }
  }

  protected void freeBuffers()
  {
    synchronized( bufSync ) {
      tmpBuf  = null;
      tmpBuf2  = null;
    }
  }

  // ----------- dependant implementation -----------

  public void dispose()
  {
//System.err.println( "DecimatedTrail.dispose() " + this );
    killAsyncThread(); // this has to be the first step
    fullScale.removeDependant( this );
    freeBuffers();
    freeTempFiles();
    super.dispose();
  }

  public final boolean isBusy()
  {
    return( (threadAsync != null) && threadAsync.isAlive() );
  }

  public final void addAsyncListener( AsyncListener l )
  {
    if( !isBusy() ) {
      l.asyncFinished( new AsyncEvent( this, AsyncEvent.FINISHED, System.currentTimeMillis(), this ));
      return;
    }
    if( asyncManager == null ) {
      asyncManager = new EventManager( new EventManager.Processor() {
        public void processEvent( BasicEvent e ) {
          final AsyncEvent  ae = (AsyncEvent) e;
          AsyncListener    al;

          for( int i = 0; i < asyncManager.countListeners(); i++ ) {
            al = (AsyncListener) asyncManager.getListener( i );
            switch( e.getID() ) {
            case AsyncEvent.UPDATE:
              al.asyncUpdate( ae );
              break;
            case AsyncEvent.FINISHED:
              al.asyncFinished( ae );
              break;
            default:
              assert false : e.getID();
              break;
            }
          }
        }
      });
    }
    asyncManager.addListener( l );
  }

  public final void removeAsyncListener( AsyncListener l )
  {
    if( asyncManager != null ) asyncManager.removeListener( l );
  }

  // ---------------------- internal classes and interfaces ----------------------

  public static interface AsyncListener {
    public void asyncFinished( AsyncEvent e );
    public void asyncUpdate( AsyncEvent e );
  }

  public static class AsyncEvent
  extends BasicEvent
  {
    protected static final int UPDATE = 0;
    protected static final int FINISHED = 1;
   
    private final DecimatedTrail t;

    protected AsyncEvent( Object source, int id, long when, DecimatedTrail t )
    {
      super( source, id, when );
      this.t  = t;
    }
   
    public DecimatedTrail getDecimatedTrail() { return t; }

    public boolean incorporate( BasicEvent oldEvent )
    {
      if( (oldEvent instanceof AsyncEvent) &&
        (this.getSource() == oldEvent.getSource()) &&
        (this.getID() == oldEvent.getID()) &&
        (t == ((AsyncEvent) oldEvent).t)) {

        return true;
      } else
        return false;
    }
  }
}
TOP

Related Classes of de.sciss.eisenkraut.io.DecimatedTrail$AsyncEvent

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.