/*
* MosaicDlg.java
* (FScape)
*
* Copyright (c) 2001-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
*
*
* Changelog:
* 20-Dec-08 created
* 20-Jun-09 audio input loops
*/
package de.sciss.fscape.gui;
import de.sciss.fscape.io.GenericFile;
import de.sciss.fscape.prop.Presets;
import de.sciss.fscape.prop.PropertyArray;
import de.sciss.fscape.session.ModulePanel;
import de.sciss.fscape.spect.ConstQ;
import de.sciss.fscape.spect.Fourier;
import de.sciss.fscape.util.Constants;
import de.sciss.fscape.util.Filter;
import de.sciss.fscape.util.Param;
import de.sciss.fscape.util.ParamSpace;
import de.sciss.fscape.util.Util;
import de.sciss.io.AudioFile;
import de.sciss.io.AudioFileDescr;
import de.sciss.io.Marker;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.image.BufferedImage;
import java.io.EOFException;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Random;
/**
* Processing module for approaching a file (fit input)
* through evolution using a genetic algorithm.
*/
public class MosaicDlg
extends ModulePanel {
// -------- private variables --------
// Properties (defaults)
private static final int PR_INIMGFILE = 0; // pr.text
private static final int PR_INMATFILE = 1;
private static final int PR_OUTPUTFILE = 2;
private static final int PR_OUTPUTTYPE = 0; // pr.intg
private static final int PR_OUTPUTRES = 1;
private static final int PR_GAINTYPE = 2;
private static final int PR_FILTERTYPE = 3;
private static final int PR_GAIN = 0; // pr.para
private static final int PR_MINFREQ = 1;
private static final int PR_MAXFREQ = 2;
private static final int PR_DURATION = 3;
private static final int PR_TIMEOVERLAP = 4;
private static final int PR_TIMEJITTER = 5;
private static final int PR_FREQOVERLAP = 6;
private static final int PR_FREQJITTER = 7;
private static final int PR_NOISEFLOOR = 8;
private static final int PR_MAXBOOST = 9;
private static final int PR_ATTACK = 10;
private static final int PR_RELEASE = 11;
private static final int PR_READMARKERS = 0; // pr.bool
private static final String PRN_INIMGFILE = "InImgFile";
private static final String PRN_OUTPUTFILE = "OutputFile";
private static final String PRN_INMATFILE = "InMatFile";
private static final String PRN_OUTPUTTYPE = "OutputType";
private static final String PRN_OUTPUTRES = "OutputReso";
private static final String PRN_FILTERTYPE = "FilterType";
private static final String PRN_MINFREQ = "MinFreq";
private static final String PRN_MAXFREQ = "MaxFreq";
private static final String PRN_DURATION = "Duration";
private static final String PRN_TIMEOVERLAP = "TimeOverlap";
private static final String PRN_TIMEJITTER = "TimeJitter";
private static final String PRN_FREQOVERLAP = "FreqOverlap";
private static final String PRN_FREQJITTER = "FreqJitter";
private static final String PRN_NOISEFLOOR = "NoiseFloor";
private static final String PRN_MAXBOOST = "MaxBoost";
private static final String PRN_ATTACK = "Attack";
private static final String PRN_RELEASE = "Release";
private static final String PRN_READMARKERS = "ReadMarkers";
private static final int FILTER_NONE = 0;
private static final int FILTER_HIGHPASS = 1;
private static final int FILTER_LOWPASS = 2;
private static final int FILTER_BANDPASS = 3;
private static final String prText[] = { "", "", "" };
private static final String prTextName[] = { PRN_INIMGFILE, PRN_INMATFILE, PRN_OUTPUTFILE };
private static final int prIntg[] = { 0, 0, GAIN_UNITY, FILTER_BANDPASS };
private static final String prIntgName[] = { PRN_OUTPUTTYPE, PRN_OUTPUTRES, PRN_GAINTYPE, PRN_FILTERTYPE };
private static final Param prPara[] = { null, null, null, null, null,
null, null, null, null, null,
null, null };
private static final String prParaName[] = { PRN_GAIN, PRN_MINFREQ, PRN_MAXFREQ, PRN_DURATION, PRN_TIMEOVERLAP,
PRN_TIMEJITTER, PRN_FREQOVERLAP, PRN_FREQJITTER, PRN_NOISEFLOOR, PRN_MAXBOOST,
PRN_ATTACK, PRN_RELEASE };
private static final boolean prBool[] = { false };
private static final String prBoolName[] = { PRN_READMARKERS };
private static final int GG_INIMGFILE = GG_OFF_PATHFIELD + PR_INIMGFILE;
private static final int GG_OUTPUTFILE = GG_OFF_PATHFIELD + PR_OUTPUTFILE;
private static final int GG_INMATFILE = GG_OFF_PATHFIELD + PR_INMATFILE;
private static final int GG_OUTPUTTYPE = GG_OFF_CHOICE + PR_OUTPUTTYPE;
private static final int GG_OUTPUTRES = GG_OFF_CHOICE + PR_OUTPUTRES;
private static final int GG_GAINTYPE = GG_OFF_CHOICE + PR_GAINTYPE;
private static final int GG_FILTERTYPE = GG_OFF_CHOICE + PR_FILTERTYPE;
private static final int GG_GAIN = GG_OFF_PARAMFIELD + PR_GAIN;
private static final int GG_MINFREQ = GG_OFF_PARAMFIELD + PR_MINFREQ;
private static final int GG_MAXFREQ = GG_OFF_PARAMFIELD + PR_MAXFREQ;
private static final int GG_DURATION = GG_OFF_PARAMFIELD + PR_DURATION;
private static final int GG_TIMEOVERLAP = GG_OFF_PARAMFIELD + PR_TIMEOVERLAP;
private static final int GG_TIMEJITTER = GG_OFF_PARAMFIELD + PR_TIMEJITTER;
private static final int GG_FREQOVERLAP = GG_OFF_PARAMFIELD + PR_FREQOVERLAP;
private static final int GG_FREQJITTER = GG_OFF_PARAMFIELD + PR_FREQJITTER;
private static final int GG_NOISEFLOOR = GG_OFF_PARAMFIELD + PR_NOISEFLOOR;
private static final int GG_MAXBOOST = GG_OFF_PARAMFIELD + PR_MAXBOOST;
private static final int GG_ATTACK = GG_OFF_PARAMFIELD + PR_ATTACK;
private static final int GG_RELEASE = GG_OFF_PARAMFIELD + PR_RELEASE;
private static final int GG_READMARKERS = GG_OFF_CHECKBOX + PR_READMARKERS;
private static PropertyArray static_pr = null;
private static Presets static_presets = null;
// private static final String ERR_MONO = "Audio file must be monophonic";
// -------- public methods --------
/**
* !! setVisible() bleibt dem Aufrufer ueberlassen
*/
public MosaicDlg()
{
super( "Mosaic" );
init2();
}
protected void buildGUI()
{
// einmalig PropertyArray initialisieren
if( static_pr == null ) {
static_pr = new PropertyArray();
static_pr.text = prText;
static_pr.textName = prTextName;
static_pr.intg = prIntg;
static_pr.intgName = prIntgName;
static_pr.bool = prBool;
static_pr.boolName = prBoolName;
static_pr.para = prPara;
static_pr.para[ PR_MINFREQ ] = new Param( 32.0, Param.ABS_HZ );
static_pr.para[ PR_MAXFREQ ] = new Param( 18000.0, Param.ABS_HZ );
static_pr.para[ PR_DURATION ] = new Param( 60000.0, Param.ABS_MS );
static_pr.para[ PR_TIMEOVERLAP ] = new Param( 100.0, Param.FACTOR_TIME );
static_pr.para[ PR_TIMEJITTER ] = new Param( 50.0, Param.FACTOR_TIME );
static_pr.para[ PR_FREQOVERLAP ] = new Param( 100.0, Param.FACTOR_FREQ );
static_pr.para[ PR_FREQJITTER ] = new Param( 50.0, Param.FACTOR_FREQ );
static_pr.para[ PR_NOISEFLOOR ] = new Param( -96.0, Param.DECIBEL_AMP );
static_pr.para[ PR_MAXBOOST ] = new Param( 96.0, Param.DECIBEL_AMP );
static_pr.para[ PR_ATTACK ] = new Param( 2.0, Param.ABS_MS );
static_pr.para[ PR_RELEASE ] = new Param( 100.0, Param.ABS_MS );
static_pr.paraName = prParaName;
// static_pr.superPr = DocumentFrame.static_pr;
fillDefaultAudioDescr( static_pr.intg, PR_OUTPUTTYPE, PR_OUTPUTRES );
fillDefaultGain( static_pr.para, PR_GAIN );
static_presets = new Presets( getClass(), static_pr.toProperties( true ));
}
presets = static_presets;
pr = (PropertyArray) static_pr.clone();
// -------- build GUI --------
final GridBagConstraints con;
final PathField ggInImgFile, ggOutputFile, ggInMatFile;
final PathField[] ggInputs;
final Component[] ggGain;
final ParamField ggDuration, ggTimeOverlap, ggMinFreq, ggMaxFreq;
final ParamField ggFreqOverlap, ggFreqJitter, ggMaxBoost, ggNoiseFloor;
final ParamField ggTimeJitter, ggAttack, ggRelease;
final JComboBox ggFilterType;
final JCheckBox ggReadMarkers;
final ParamSpace[] spcAtkRls;
gui = new GUISupport();
con = gui.getGridBagConstraints();
con.insets = new Insets( 1, 2, 1, 2 );
final ItemListener il = new ItemListener() {
public void itemStateChanged( ItemEvent e )
{
int ID = gui.getItemID( e );
switch( ID ) {
case GG_READMARKERS:
pr.bool[ ID - GG_OFF_CHECKBOX ] = ((JCheckBox) e.getSource()).isSelected();
reflectPropertyChanges();
break;
}
}
};
// -------- Input-Gadgets --------
con.fill = GridBagConstraints.BOTH;
con.gridwidth = GridBagConstraints.REMAINDER;
gui.addLabel( new GroupLabel( "Waveform I/O", GroupLabel.ORIENT_HORIZONTAL,
GroupLabel.BRACE_NONE ));
ggInImgFile = new PathField( PathField.TYPE_INPUTFILE /* + PathField.TYPE_FORMATFIELD */,
"Select input image file" );
// ggInImgFile.handleTypes( GenericFile.TYPES_IMAGE );
con.gridwidth = 1;
con.weightx = 0.1;
gui.addLabel( new JLabel( "Image input", SwingConstants.RIGHT ));
con.gridwidth = GridBagConstraints.REMAINDER;
con.weightx = 0.9;
gui.addPathField( ggInImgFile, GG_INIMGFILE, null );
ggInMatFile = new PathField( PathField.TYPE_INPUTFILE + PathField.TYPE_FORMATFIELD,
"Select input audio file" );
ggInMatFile.handleTypes( GenericFile.TYPES_SOUND );
con.gridwidth = 1;
con.weightx = 0.1;
gui.addLabel( new JLabel( "Audio input", SwingConstants.RIGHT ));
con.gridwidth = GridBagConstraints.REMAINDER;
con.weightx = 0.9;
gui.addPathField( ggInMatFile, GG_INMATFILE, null );
ggOutputFile = new PathField( PathField.TYPE_OUTPUTFILE + PathField.TYPE_FORMATFIELD +
PathField.TYPE_RESFIELD, "Select output file" );
ggOutputFile.handleTypes( GenericFile.TYPES_SOUND );
ggInputs = new PathField[ 2 ];
ggInputs[ 0 ] = ggInImgFile;
ggInputs[ 1 ] = ggInMatFile;
ggOutputFile.deriveFrom( ggInputs, "$D0$B0Mos$B1$E" );
con.gridwidth = 1;
con.weightx = 0.1;
gui.addLabel( new JLabel( "Mosaic output", SwingConstants.RIGHT ));
con.gridwidth = GridBagConstraints.REMAINDER;
con.weightx = 0.9;
gui.addPathField( ggOutputFile, GG_OUTPUTFILE, null );
gui.registerGadget( ggOutputFile.getTypeGadget(), GG_OUTPUTTYPE );
gui.registerGadget( ggOutputFile.getResGadget(), GG_OUTPUTRES );
ggGain = createGadgets( GGTYPE_GAIN );
con.weightx = 0.1;
con.gridwidth = 1;
gui.addLabel( new JLabel( "Gain", SwingConstants.RIGHT ));
con.weightx = 0.4;
gui.addParamField( (ParamField) ggGain[ 0 ], GG_GAIN, null );
con.weightx = 0.5;
con.gridwidth = GridBagConstraints.REMAINDER;
gui.addChoice( (JComboBox) ggGain[ 1 ], GG_GAINTYPE, il );
// -------- Plot Settings --------
gui.addLabel( new GroupLabel( "Settings", GroupLabel.ORIENT_HORIZONTAL,
GroupLabel.BRACE_NONE ));
ggDuration = new ParamField( Constants.spaces[ Constants.absMsSpace ]);
con.weightx = 0.1;
con.gridwidth = 1;
gui.addLabel( new JLabel( "Nominal Duration", SwingConstants.RIGHT ));
con.weightx = 0.4;
gui.addParamField( ggDuration, GG_DURATION, null );
ggMinFreq = new ParamField( Constants.spaces[ Constants.absHzSpace ]);
con.weightx = 0.1;
gui.addLabel( new JLabel( "Min Freq.", SwingConstants.RIGHT ));
con.weightx = 0.4;
con.gridwidth = GridBagConstraints.REMAINDER;
gui.addParamField( ggMinFreq, GG_MINFREQ, null );
ggFilterType = new JComboBox();
ggFilterType.addItem( "None" );
ggFilterType.addItem( "Highpass" );
ggFilterType.addItem( "Lowpass" );
ggFilterType.addItem( "Bandpass" );
con.weightx = 0.1;
con.gridwidth = 1;
gui.addLabel( new JLabel( "Filter Type", SwingConstants.RIGHT ));
con.weightx = 0.2;
gui.addChoice( ggFilterType, GG_FILTERTYPE, il );
ggMaxFreq = new ParamField( Constants.spaces[ Constants.absHzSpace ]);
con.weightx = 0.1;
con.gridwidth = 1;
gui.addLabel( new JLabel( "Max Freq.", SwingConstants.RIGHT ));
con.weightx = 0.4;
con.gridwidth = GridBagConstraints.REMAINDER;
gui.addParamField( ggMaxFreq, GG_MAXFREQ, null );
ggReadMarkers = new JCheckBox();
con.weightx = 0.1;
con.gridwidth = 1;
gui.addLabel( new JLabel( "Read Markers", SwingConstants.RIGHT ));
con.weightx = 0.4;
con.gridwidth = GridBagConstraints.REMAINDER;
gui.addCheckbox( ggReadMarkers, GG_READMARKERS, il );
ggTimeOverlap = new ParamField( Constants.spaces[ Constants.factorTimeSpace ]);
con.weightx = 0.1;
con.gridwidth = 1;
gui.addLabel( new JLabel( "Time Spacing", SwingConstants.RIGHT ));
con.weightx = 0.4;
gui.addParamField( ggTimeOverlap, GG_TIMEOVERLAP, null );
ggFreqOverlap = new ParamField(
new ParamSpace( 100.0, 1000000.0, 0.01, Param.FACTOR_FREQ ));
con.weightx = 0.1;
gui.addLabel( new JLabel( "Freq Spacing", SwingConstants.RIGHT ));
con.weightx = 0.4;
con.gridwidth = GridBagConstraints.REMAINDER;
gui.addParamField( ggFreqOverlap, GG_FREQOVERLAP, null );
ggTimeJitter = new ParamField( Constants.spaces[ Constants.factorTimeSpace ]);
con.weightx = 0.1;
con.gridwidth = 1;
gui.addLabel( new JLabel( "Time Jitter", SwingConstants.RIGHT ));
con.weightx = 0.4;
gui.addParamField( ggTimeJitter, GG_TIMEJITTER, null );
ggFreqJitter = new ParamField( Constants.spaces[ Constants.factorFreqSpace ]);
con.weightx = 0.1;
gui.addLabel( new JLabel( "Freq Jitter", SwingConstants.RIGHT ));
con.weightx = 0.4;
con.gridwidth = GridBagConstraints.REMAINDER;
gui.addParamField( ggFreqJitter, GG_FREQJITTER, null );
ggMaxBoost = new ParamField( Constants.spaces[ Constants.decibelAmpSpace ]);
con.weightx = 0.1;
con.gridwidth = 1;
gui.addLabel( new JLabel( "Max Boost", SwingConstants.RIGHT ));
con.weightx = 0.4;
gui.addParamField( ggMaxBoost, GG_MAXBOOST, null );
spcAtkRls = new ParamSpace[] {
Constants.spaces[ Constants.absMsSpace ],
Constants.spaces[ Constants.factorTimeSpace ]};
ggAttack = new ParamField( spcAtkRls );
con.weightx = 0.1;
gui.addLabel( new JLabel( "Attack", SwingConstants.RIGHT ));
con.weightx = 0.4;
con.gridwidth = GridBagConstraints.REMAINDER;
gui.addParamField( ggAttack, GG_ATTACK, null );
ggNoiseFloor = new ParamField( Constants.spaces[ Constants.decibelAmpSpace ]);
con.weightx = 0.1;
con.gridwidth = 1;
gui.addLabel( new JLabel( "Noise Floor", SwingConstants.RIGHT ));
con.weightx = 0.4;
gui.addParamField( ggNoiseFloor, GG_NOISEFLOOR, null );
ggRelease = new ParamField( spcAtkRls );
con.weightx = 0.1;
gui.addLabel( new JLabel( "Release", SwingConstants.RIGHT ));
con.weightx = 0.4;
con.gridwidth = GridBagConstraints.REMAINDER;
gui.addParamField( ggRelease, GG_RELEASE, null );
// ggElitism = new JCheckBox();
// con.weightx = 0.1;
// con.gridwidth = 1;
// gui.addLabel( new JLabel( "Elitism", SwingConstants.RIGHT ));
// con.weightx = 0.2;
// gui.addCheckbox( ggElitism, GG_ELITISM, il );
initGUI( this, FLAGS_PRESETS | FLAGS_PROGBAR, gui );
}
/**
* Transfer values from prop-array to GUI
*/
public void fillGUI()
{
super.fillGUI();
super.fillGUI( gui );
}
/**
* Transfer values from GUI to prop-array
*/
public void fillPropertyArray()
{
super.fillPropertyArray();
super.fillPropertyArray( gui );
}
// -------- Processor Interface --------
protected void process()
{
long progOff;
final long progLen;
BufferedImage img = null;
AudioFile outF = null;
AudioFile inMatF = null;
final AudioFile tmpF;
final AudioFileDescr outStream;
final AudioFileDescr inMatDescr;
final int inChanNum;
final long inMatLength;
final Param ampRef = new Param( 1.0, Param.ABS_AMP ); // transform-Referenz
float gain = 1.0f; // gain abs amp
float maxAmp = 0.0f;
final PathField ggOutput;
final Random rnd = new Random();
int chunkLen, chunkLen2;
final ConstQ constQ;
final double minFreq = pr.para[ PR_MINFREQ ].value;
final double maxFreq = pr.para[ PR_MAXFREQ ].value;
final double duration = pr.para[ PR_DURATION ].value;
final int width, height;
final double framesPerPixel;
final double timeOverlap = pr.para[ PR_TIMEOVERLAP ].value / 100;
final double freqOverlap = pr.para[ PR_FREQOVERLAP ].value / 100;
final int fltType = pr.intg[ PR_FILTERTYPE ];
final boolean readMarkers = pr.bool[ PR_READMARKERS ];
final int inBufSize, largestWinSize;
final float[][] inBuf, mixBuf;
final int fftSize;
final float[][] kernels;
final float timeRes = 20.0f; // ... subject to configuration?
final int stepSize;
final int numKernels, kernelsPerPixel;
final float[] tmpKernel;
final int numRMS, numRMS10, numRMS90;
final double[] rmss, vars;
final Integer[] indices, sortedIndices;
final float[] hsb = new float[ 3 ];
final double timeJitter = pr.para[ PR_TIMEJITTER ].value / 100;
final double freqJitter = pr.para[ PR_FREQJITTER ].value / 100;
final double maxBoost = (Param.transform( pr.para[ PR_MAXBOOST ], Param.ABS_AMP, ampRef, null )).value;
final double noiseFloor = (Param.transform( pr.para[ PR_NOISEFLOOR ], Param.ABS_AMP, ampRef, null )).value;
final double nyquist;
final List<Marker> markers;
final int largestNumSteps;
Param pWinSize;
int atkLen = -1;
int rlsLen = -1;
float[] atkWin = null;
float[] rlsWin = null;
double d1, d2, bestVar, bestRMS;
float f1, f2, f3, chunkGain;
int i1, i2, rgb, percentile, idx, bestIdx;
int winSize, markIdx, numSteps;
double midMatFreq, midImgFreq;
long outOff, lastMarkPos, n1, n2, framePos;
float brightness;
Marker mark;
// karlheinz hilbert
double hlbFltFreq, hlbFltShift, hlbShiftFreq;
FilterBox hlbFltBox;
Point hlbFltLen;
int hlbSkip, hlbFFTLen, hlbInputLen, hlbChunkLen;
int hlbChunkLen2, hlbOverLen;
float[] hlbFFTBuf1, hlbFFTBuf2;
float[][] hlbOverBuf;
long hlbTotalInLen, hlbFramesRead, hlbFramesWritten, hlbFramePos;
// karlheinz filter
final int fltNumPeriods = 6;
final double fltFreqNorm, fltCosineNorm;
float[][] fltOverBuf;
float[] fltWin, fltFFTBuf1, fltFFTBuf2;
double fltLowFreq, fltHighFreq, fltLowCosFreq, fltHighCosFreq;
int fltFFTLen, fltHalfWinSize, fltInputLen;
int fltOverLen, fltLength;
double fltFreqBase, fltCosineBase, fltJitter;
long fltFramesRead, fltFramesWritten, fltTotalInLen;
int fltSkip, fltChunkLen, fltChunkLen2;
topLevel: try {
// ---- open input, output; init ----
// input
img = ImageIO.read( new File( pr.text[ PR_INIMGFILE ]));
if( img == null ) throw new IOException( "No matching image decoder found" );
// .... check running ....
if( !threadRunning ) break topLevel;
// ptrn input
inMatF = AudioFile.openAsRead( new File( pr.text[ PR_INMATFILE ]));
inMatDescr = inMatF.getDescr();
inChanNum = inMatDescr.channels;
inMatLength = inMatDescr.length;
// this helps to prevent errors from empty files!
if( (inMatLength < 1) || (inChanNum < 1) ) throw new EOFException( ERR_EMPTY );
// if( inPopChanNum != 1 ) throw new EOFException( ERR_MONO );
// .... check running ....
if( !threadRunning ) break topLevel;
// if( inChanNum > 1 ) {
// System.out.println( "WARNING: Multichannel input. Using mono mix for mosaic correlation!" );
// }
// output
ggOutput = (PathField) gui.getItemObj( GG_OUTPUTFILE );
if( ggOutput == null ) throw new IOException( ERR_MISSINGPROP );
outStream = new AudioFileDescr( inMatDescr );
ggOutput.fillStream( outStream );
outF = AudioFile.openAsWrite( outStream );
// .... check running ....
if( !threadRunning ) break topLevel;
// ---- further inits ----
constQ = new ConstQ();
constQ.setSampleRate( inMatDescr.rate );
constQ.setMinFreq( (float) minFreq );
constQ.setMaxFreq( (float) maxFreq );
constQ.setMaxFFTSize( 8192 );
constQ.setMaxTimeRes( timeRes );
constQ.createKernels();
fftSize = constQ.getFFTSize();
numKernels = constQ.getNumKernels();
if( pr.intg[ PR_GAINTYPE ] == GAIN_ABSOLUTE ) {
gain = (float) (Param.transform( pr.para[ PR_GAIN ], Param.ABS_AMP, ampRef, null )).value;
}
tmpF = createTempFile( outStream );
width = img.getWidth();
height = img.getHeight();
// framesPerPixel = (double) inMatDescr.length / width;
framesPerPixel = AudioFileDescr.millisToSamples( inMatDescr, duration ) / width;
if( readMarkers ) {
inMatF.readMarkers();
markers = (List<Marker>) inMatDescr.getProperty( AudioFileDescr.KEY_MARKERS );
if( markers == null || markers.isEmpty() ) throw new IOException( "Soundfile does not contain markers" );
Collections.sort( markers );
mark = (Marker) markers.get( 0 );
if( mark.pos == 0 ) markers.remove( 0 );
mark = (Marker) markers.get( markers.size() - 1 );
if( mark.pos < inMatLength ) markers.add( new Marker( inMatLength, "End" ));
i1 = 0;
lastMarkPos = 0;
for( int i = 0; i < markers.size(); i++ ) {
n2 = ((Marker) markers.get( i )).pos;
i1 = Math.max( i1, (int) (n2 - lastMarkPos) );
lastMarkPos = n2;
}
largestWinSize = i1;
} else {
largestWinSize = (int) (framesPerPixel * timeOverlap + 0.5);
markers = null;
}
inBufSize = Math.max( 8192, largestWinSize );
stepSize = (int) (AudioFileDescr.millisToSamples( inMatDescr, timeRes ) + 0.5);
largestNumSteps = Math.max( 0, largestWinSize - fftSize ) / stepSize + 1;
inBuf = new float[ inChanNum ][ inBufSize ];
mixBuf = new float[ inChanNum ][ inBufSize ];
kernels = new float[ largestNumSteps ][ numKernels ];
tmpKernel = new float[ numKernels ];
kernelsPerPixel = (int) ((double) numKernels / height + 0.5);
numRMS = Math.max( 0, numKernels - kernelsPerPixel ) + 1;
numRMS90 = (int) (numRMS * 0.9 + 0.5);
numRMS10 = numRMS - numRMS90;
rmss = new double[ numRMS ];
vars = new double[ numRMS ];
sortedIndices = new Integer[ numRMS ];
for( int i = 0; i < numRMS; i++ ) {
sortedIndices[ i ] = new Integer( i );
}
indices = new Integer[ numRMS ];
// pWinSize = new Param( AudioFileDescr.samplesToMillis( outStream, winSize ), Param.ABS_MS );
// atkLen = Math.min( winSize, (int) (AudioFileDescr.millisToSamples( outStream, Param.transform( pr.para[ PR_ATTACK ], Param.ABS_MS, pWinSize, null ).value ) + 0.5) );
// rlsLen = Math.min( winSize - atkLen, (int) (AudioFileDescr.millisToSamples( outStream, Param.transform( pr.para[ PR_RELEASE ], Param.ABS_MS, pWinSize, null ).value ) + 0.5) );
// atkWin = Filter.createWindow( atkLen, Filter.WIN_HANNING );
// Util.reverse( atkWin, 0, atkLen );
// rlsWin = Filter.createWindow( rlsLen, Filter.WIN_HANNING );
//System.out.println( "atkLen " + atkLen + "; rlsLen " + rlsLen + "; winSize " + winSize );
//Debug.view( atkWin, 0, atkLen, "Atk", true, false );
//Debug.view( rlsWin, 0, rlsLen, "Rls", true, false );
nyquist = (inMatDescr.rate/2);
fltFreqNorm = Math.PI / nyquist;
fltCosineNorm = 4.0 / (Math.PI*Math.PI);
progLen = ((width + 1) * height * inBufSize);
progOff = 0;
lastMarkPos = 0;
markIdx = 0;
winSize = largestWinSize;
// ----==================== processing loop ====================----
for( int x = 0; x < width; x++ ) {
lpY: for( int y = 0; threadRunning && (y < height); y++ ) {
//System.out.println( "x = " + x + "; y = " + y );
rgb = img.getRGB( x, y );
Color.RGBtoHSB( (rgb >> 16) & 0xFF, (rgb >> 8) & 0xFF, rgb & 0xFF, hsb );
brightness = hsb[ 2 ];
if( brightness == 0f ) {
progOff += inBufSize;
continue lpY;
}
// inMatF.seekFrame( (long) (x * framesPerPixel + 0.5) );
framePos = inMatF.getFramePosition();
if( readMarkers ) {
if( markIdx == markers.size() ) {
markIdx = 0;
lastMarkPos = 0L;
inMatF.seekFrame( 0L );
}
n1 = ((Marker) markers.get( markIdx++ )).pos;
winSize = (int) (n1 - lastMarkPos);
lastMarkPos = n1;
} else if( framePos == inMatLength ) {
inMatF.seekFrame( 0L );
}
chunkLen = (int) Math.min( inMatLength - framePos, winSize );
inMatF.readFrames( inBuf, 0, chunkLen );
// if( chunkLen < winSize ) {
// Util.clear( inBuf, chunkLen, winSize - chunkLen );
// }
// XXX mult with hanning window
// Util.clear( rmss );
// Util.clear( vars );
for( int i = 0; i < numRMS; i++ ) {
rmss[ i ] = 0.0;
vars[ i ] = 0.0;
}
numSteps = Math.max( 0, winSize - fftSize ) / stepSize + 1;
for( int step = 0, stepOff = 0; step < numSteps; step++, stepOff += stepSize ) {
chunkLen2 = Math.max( 0, Math.min( fftSize, chunkLen - stepOff ));
constQ.transform( inBuf[ 0 ], stepOff, chunkLen2, kernels[ step ], 0 );
for( int ch = 1; ch < inChanNum; ch++ ) {
constQ.transform( inBuf[ ch ], stepOff, chunkLen2, tmpKernel, 0 );
Util.add( tmpKernel, 0, kernels[ step ], 0, numKernels );
}
d1 = 0.0; d2 = 0.0;
f2 = Util.mean( kernels[ step ], 0, numKernels );
for( int i = 0; i < kernelsPerPixel; i++ ) {
f1 = kernels[ step ][ i ];
f3 = f1 - f2;
d1 += f1 * f1;
d2 += f3 * f3;
}
rmss[ 0 ] += d1;
vars[ 0 ] += d2;
for( int i = 1, j = kernelsPerPixel; i < numRMS; i++, j++ ) {
f1 = kernels[ step ][ j - kernelsPerPixel ];
f3 = f1 - f2;
d1 -= f1 * f1;
d2 -= f3 * f3;
f1 = kernels[ step ][ j ];
f3 = f1 - f2;
d1 += f1 * f1;
d2 += f3 * f3;
rmss[ i ] += d1;
vars[ i ] += d2;
}
}
System.arraycopy( sortedIndices, 0, indices, 0, numRMS );
Util.sort( rmss, indices, 0, numRMS );
percentile = (int) (brightness * numRMS90 + numRMS10 + 0.5f);
bestIdx = -1;
bestVar = Double.POSITIVE_INFINITY;
bestRMS = 0.0;
for( int i = numRMS - percentile; i < numRMS; i++ ) {
idx = indices[ i ].intValue();
if( vars[ idx ] < bestVar ) {
bestVar = vars[ idx ];
bestRMS = rmss[ idx ];
bestIdx = idx;
}
}
// midMatFreq = Util.linexp( bestIdx + kernelsPerPixelH, 0, numRMS, minFreq, maxFreq );
midMatFreq = Util.linexp( bestIdx, 0, numRMS - 1, minFreq, maxFreq );
midImgFreq = Util.linexp( y, height - 1, 0, minFreq, maxFreq );
// hlbShiftFreq = Math.abs( midImgFreq - midMatFreq );
hlbShiftFreq = midImgFreq - midMatFreq;
hlbTotalInLen = chunkLen;
// =================================================================
// =============== here comes the hilbert shift part ===============
// =================================================================
//if( x == 51 && y == 23 ) {
// Debug.view( inBuf[ 0 ], 0, 1000, "In x = " + x + "; y = " + y, true, false );
//}
hlbFltFreq = inMatDescr.rate * 0.245; // account for lp transition band
hlbFltShift = hlbFltFreq;
hlbFltShift *= Constants.PI2 / inMatDescr.rate; // normalized freq ready for Math.cos/sin
hlbShiftFreq *= Constants.PI2 / inMatDescr.rate;
hlbFltBox = new FilterBox();
hlbFltBox.filterType= FilterBox.FLT_LOWPASS;
hlbFltBox.cutOff = new Param( hlbFltFreq, Param.ABS_HZ );
hlbFltLen = hlbFltBox.calcLength( inMatDescr, FIRDesignerDlg.QUAL_VERYGOOD );
hlbSkip = hlbFltLen.x * 2; // support not written out
i1 = (hlbFltLen.x + hlbFltLen.y) * 2 - 1; // length after conv. filter with itself
i2 = i1 + i1 - 1; // length after conv. with input
for( hlbFFTLen = 2; hlbFFTLen < i2; hlbFFTLen <<= 1 ) ;
hlbInputLen = hlbFFTLen - i1 - 1; // + 1
hlbFFTBuf1 = new float[ hlbFFTLen << 1 ];
hlbFFTBuf2 = new float[ hlbFFTLen << 1 ];
// hlbReBuf = new float[ inChanNum ][ hlbFFTLen + 2 ];
hlbOverLen = hlbFFTLen - hlbInputLen;
hlbOverBuf = new float[ inChanNum ][ hlbOverLen ];
// we design a half-nyquist lp filter and shift it up by that freq. to have a real=>analytic filter
// see comp.dsp algorithms-faq Q2.10
hlbFltBox.calcIR( inMatDescr, FIRDesignerDlg.QUAL_VERYGOOD, Filter.WIN_BLACKMAN, hlbFFTBuf1, hlbFltLen );
Fourier.realTransform( hlbFFTBuf1, hlbFFTLen, Fourier.FORWARD );
// ---- "medium"-length sinc-lp convolved with itself produces a sharp and non-overshooting filter! ----
for( int i = 0; i <= hlbFFTLen; i += 2 ) {
d1 = hlbFFTBuf1[ i ];
d2 = hlbFFTBuf1[ i + 1 ];
hlbFFTBuf1[ i ]= (float) (d1*d1 - d2*d2); // complex mult
hlbFFTBuf1[ i + 1 ]= (float) (2*d1*d2);
}
Fourier.realTransform( hlbFFTBuf1, hlbFFTLen, Fourier.INVERSE );
// ---- real=>complex + modulation with exp(ismpRate/4 +/- (?) antialias) ----
// k is chosen so that the filter-centre is zero degrees, otherwise we introduce phase shift
for( int i = hlbFFTLen - 1, k = i - hlbFltLen.x, j = hlbFFTBuf1.length - 1; i >= 0; i--, k-- ) {
d1 = -hlbFltShift * k;
hlbFFTBuf1[ j-- ] = (float) (hlbFFTBuf1[ i ] * Math.sin( d1 )); // img
hlbFFTBuf1[ j-- ] = (float) (hlbFFTBuf1[ i ] * Math.cos( d1 )); // real
}
Fourier.complexTransform( hlbFFTBuf1, hlbFFTLen, Fourier.FORWARD );
hlbFramesRead = 0;
hlbFramesWritten = 0;
while( threadRunning && (hlbFramesWritten < hlbTotalInLen) ) {
hlbChunkLen = (int) Math.min( hlbInputLen, hlbTotalInLen - hlbFramesRead );
hlbChunkLen2 = (int) Math.min( hlbInputLen, hlbTotalInLen - hlbFramesWritten );
// // fake read in
// for( int ch = 0; ch < inChanNum; ch++ ) {
// convBuf1 = hlbReBuf[ ch ];
// System.arraycopy( inBuf[ ch ], (int) hlbFramesRead, convBuf1, 0, hlbChunkLen );
// for( int i = hlbChunkLen; i < convBuf1.length; i++ ) {
// convBuf1[ i ] = 0f;
// }
// }
for( int ch = 0; ch < inChanNum; ch++ ) {
// fake read
//if( x == 8 && y == 12 ) {
// System.out.println( "ch = " + ch + "; copying from inBuf (" + hlbFramesRead + ") to fftBuf (0), len = " + hlbChunkLen );
//}
if( hlbChunkLen > 0 ) {
System.arraycopy( inBuf[ ch ], (int) hlbFramesRead, hlbFFTBuf2, 0, hlbChunkLen );
for( int i = hlbChunkLen; i < hlbFFTLen; i++ ) {
hlbFFTBuf2[ i ] = 0.0f;
}
// ---- real fft input + convert to complex + convolve with filter + ifft ----
Fourier.realTransform( hlbFFTBuf2, hlbFFTLen, Fourier.FORWARD );
for( int i = hlbFFTLen, j = hlbFFTLen; i > 0; i -= 2, j += 2 ) { // neg.freq. complex conjugate
hlbFFTBuf2[ j ] = hlbFFTBuf2[ i ];
hlbFFTBuf2[ j+1 ] = -hlbFFTBuf2[ i+1 ];
}
Fourier.complexMult( hlbFFTBuf1, 0, hlbFFTBuf2, 0, hlbFFTBuf2, 0, hlbFFTLen << 1 );
Fourier.complexTransform( hlbFFTBuf2, hlbFFTLen, Fourier.INVERSE );
// ---- post proc ----
hlbFramePos = hlbFramesRead; // hlbFramesWritten;
for( int i = 0, j = 0; i < hlbFFTLen; i++ ) {
d1 = hlbShiftFreq * hlbFramePos++;
hlbFFTBuf2[ i ] = (float) (hlbFFTBuf2[ j++ ] * Math.cos( d1 ) + hlbFFTBuf2[ j++ ] * Math.sin( d1 ));
}
} else {
Util.clear( hlbFFTBuf2 );
}
// ---- handle overlaps ----
Util.add( hlbOverBuf[ ch ], 0, hlbFFTBuf2, 0, hlbOverLen );
//// System.arraycopy( hlbReBuf[ ch ], hlbInputLen, hlbOverBuf[ ch ], 0, hlbFFTLen - hlbInputLen );
// System.arraycopy( hlbFFTBuf2, hlbChunkLen, hlbOverBuf[ ch ], 0, hlbOverLen );
System.arraycopy( hlbFFTBuf2, hlbChunkLen2, hlbOverBuf[ ch ], 0, hlbOverLen );
// fake write
System.arraycopy( hlbFFTBuf2, hlbSkip, inBuf[ ch ], (int) hlbFramesWritten, Math.max( 0, hlbChunkLen2 - hlbSkip ));
} // for channels
// // fake write out
// for( int ch = 0; ch < inChanNum; ch++ ) {
// convBuf1 = hlbReBuf[ ch ];
// System.arraycopy( convBuf1, hlbSkip, inBuf[ ch ], (int) hlbFramesWritten, hlbChunkLen2 - hlbSkip );
// }
hlbFramesRead += hlbChunkLen;
hlbFramesWritten += Math.max( 0, hlbChunkLen2 - hlbSkip );
if( hlbSkip > 0 ) {
hlbSkip = Math.max( 0, hlbSkip - hlbChunkLen2 );
}
} // until framesWritten == outLength
//if( x == 51 && y == 23 ) {
// Debug.view( inBuf[ 0 ], 0, 1000, "Hlb x = " + x + "; y = " + y, true, false );
//}
fltTotalInLen = chunkLen;
// ============================================================
// =============== here comes the bandpass part ===============
// ============================================================
if( fltType != FILTER_NONE ) {
// LP = +1.0 fc -1.0 Zero
// HP = +1.0 pi/2 -1.0 fc
// BP = +1.0 fc2 -1.0 fc1
fltJitter = (rnd.nextDouble() * 2 - 1) * freqJitter;
if( fltType == FILTER_LOWPASS ) {
fltLowFreq = 0.0f;
fltLowCosFreq = 0.0f;
} else {
fltLowFreq = Math.max( 0.0,
Util.linexp( y + fltJitter - 0.5, height - 1, 0, minFreq, maxFreq ));
fltLowCosFreq = fltLowFreq - Math.max( 0.0,
Util.linexp( y + fltJitter - 0.5 - (freqOverlap - 1.0), height - 1, 0, minFreq, maxFreq ));
}
if( fltType == FILTER_HIGHPASS ) {
fltHighFreq = nyquist;
fltHighCosFreq = 0.0;
} else {
fltHighFreq = Math.min( nyquist,
Util.linexp( y + fltJitter + 0.5, height - 1, 0, minFreq, maxFreq ));
fltHighCosFreq = Math.min( nyquist,
Util.linexp( y + fltJitter + 0.5 + (freqOverlap - 1.0), height - 1, 0, minFreq, maxFreq ))
- fltHighFreq;
}
// fltCosineFreqs = new float[ numBands+1 ];
// fltCosineFreqs[0] = 0.0f;
// fltCosineFreqs[numBands] = 0.0f;
// for( int i = 1; i < numBands; i++ ) {
// d1 = Math.sqrt( fltCrossFreqs[i-1] * fltCrossFreqs[i] ) - fltCrossFreqs[i-1]; // middle freq - lower freq
// d2 = Math.sqrt( fltCrossFreqs[i] * fltCrossFreqs[i+1] ) - fltCrossFreqs[i];
// fltCosineFreqs[i] = Math.max( 0.0f, (float) (Math.min( d1, d2 ) * fltRollOff ));
// }
// fltLowCosFreq = (float) (Math.sqrt( fltLowFreq * fltHighFreq ) - fltLowFreq);
// fltLowCosFreq = 0.0f; // XXX
// fltHighCosFreq = 0.0f; // XXX
// fltNumPeriods = 6;
fltHalfWinSize = Math.max( 1, (int) ((double) fltNumPeriods * inMatDescr.rate / fltHighFreq + 0.5) );
fltLength = fltHalfWinSize + fltHalfWinSize;
fltWin = Filter.createFullWindow( fltLength, Filter.WIN_BLACKMAN );
i1 = fltLength + fltLength - 1;
for( fltFFTLen = 2; fltFFTLen < i1; fltFFTLen <<= 1 ) ;
fltInputLen = fltFFTLen - fltLength + 1;
fltOverLen = fltFFTLen - fltInputLen;
//if( x == 51 && y == 23 ) {
// System.out.println( "Filter: loFreq " + fltLowFreq + "; hiFreq " + fltHighFreq + "; loCosFreq " + fltLowCosFreq + "; hiCosFreq " + fltHighCosFreq );
// System.out.println( " fltHalfWinSize " + fltHalfWinSize + "; fltFFTLen " + fltFFTLen + "; fltInputLen " + fltInputLen + "; fltOverLen " + fltOverLen + "; fltTotalInLen " + fltTotalInLen );
//}
// fltFFTBuf = new float[ numBands ][ fltFFTLen + 2 ];
fltFFTBuf1 = new float[ fltFFTLen + 2 ];
fltFFTBuf2 = new float[ fltFFTLen + 2 ];
// fltInBuf = new float[ inChanNum ][ fltInputLen ];
fltOverBuf = new float[ inChanNum ][ fltOverLen ];
// calculate impulse response of the bandpass
fltFreqBase = fltFreqNorm * fltHighFreq;
fltCosineBase = fltFreqNorm * fltHighCosFreq;
for( int j = 1; j < fltHalfWinSize; j++ ) {
// sinc-filter
d1 = (Math.sin( fltFreqBase * j ) / (double) j);
// raised cosine modulation
d2 = fltCosineNorm * fltCosineBase * j * fltCosineBase * j;
d1 *= (Math.cos( fltCosineBase * j ) / (1.0 - d2));
fltFFTBuf1[ fltHalfWinSize + j ] = (float) d1;
fltFFTBuf1[ fltHalfWinSize - j ] = (float) d1;
}
fltFFTBuf1[ fltHalfWinSize ] = (float) fltFreqBase;
fltFreqBase = fltFreqNorm * fltLowFreq;
fltCosineBase = fltFreqNorm * fltLowCosFreq;
for( int j = 1; j < fltHalfWinSize; j++ ) {
d1 = (Math.sin( fltFreqBase * j ) / (double) j);
// raised cosine modulation
d2 = fltCosineNorm * fltCosineBase * j * fltCosineBase * j;
d1 *= (Math.cos( fltCosineBase * j ) / (1.0 - d2));
fltFFTBuf1[ fltHalfWinSize + j ] -= (float) d1;
fltFFTBuf1[ fltHalfWinSize - j ] -= (float) d1;
}
fltFFTBuf1[ fltHalfWinSize ] -= (float) fltFreqBase;
// zero padding
for( int j = fltLength; j < fltFFTLen; j++ ) {
fltFFTBuf1[ j ] = 0.0f;
}
// windowing
Util.mult( fltWin, 0, fltFFTBuf1, 0, fltLength );
//if( x == 51 && y == 23 ) {
// Debug.view( fltFFTBuf1, 0, fltLength, "Filter Time Signal", true, false );
//}
Fourier.realTransform( fltFFTBuf1, fltFFTLen, Fourier.FORWARD );
fltFramesRead = 0;
fltFramesWritten = 0;
fltSkip = fltHalfWinSize;
while( threadRunning && (fltFramesWritten < fltTotalInLen) ) {
fltChunkLen = (int) Math.min( fltInputLen, fltTotalInLen - fltFramesRead );
fltChunkLen2 = (int) Math.min( fltInputLen, fltTotalInLen - fltFramesWritten );
//if( x == 51 && y == 23 ) {
// System.out.println( "fltChunkLen = " + fltChunkLen + " ; fltChunkLen2 = " + fltChunkLen2 + "; fltFramesRead = " + fltFramesRead + "; fltFramesWritten " + fltFramesWritten );
//}
// ---- channels loop -----------------------------------------------------------------------
for( int ch = 0; threadRunning && (ch < inChanNum); ch++ ) {
// fake read
//if( x == 51 && y == 23 ) {
// System.out.println( "ch = " + ch + "; copying from inBuf (" + fltFramesRead + ") to fftBuf (0), len = " + fltChunkLen );
//}
if( fltChunkLen > 0 ) {
System.arraycopy( inBuf[ ch ], (int) fltFramesRead, fltFFTBuf2, 0, fltChunkLen );
for( int i = fltChunkLen; i < fltFFTLen; i++ ) {
fltFFTBuf2[ i ] = 0.0f;
}
Fourier.realTransform( fltFFTBuf2, fltFFTLen, Fourier.FORWARD );
Fourier.complexMult( fltFFTBuf2, 0, fltFFTBuf1, 0, fltFFTBuf2, 0, fltFFTBuf1.length );
Fourier.realTransform( fltFFTBuf2, fltFFTLen, Fourier.INVERSE );
//if( x == 51 && y == 23 ) {
// System.out.println( "adding from fltOverBuf (0) to fftBuf (0), len = " + fltOverLen );
//// System.out.println( "copying from fftBuf (" + fltChunkLen + ") to fltOverBuf( 0 ), len = " + fltOverLen );
// System.out.println( "copying from fftBuf (" + fltChunkLen2 + ") to fltOverBuf( 0 ), len = " + fltOverLen );
// System.out.println( "copying from fftBuf (" + fltSkip + ") to inBuf( " + fltFramesWritten + " ), len = " + Math.max( 0, fltChunkLen2 - fltSkip ) );
//}
} else {
Util.clear( fltFFTBuf2 );
}
Util.add( fltOverBuf[ ch ], 0, fltFFTBuf2, 0, fltOverLen );
// System.arraycopy( fltFFTBuf2, fltChunkLen, fltOverBuf[ ch ], 0, fltOverLen );
System.arraycopy( fltFFTBuf2, fltChunkLen2, fltOverBuf[ ch ], 0, fltOverLen );
// fake write
System.arraycopy( fltFFTBuf2, fltSkip, inBuf[ ch ], (int) fltFramesWritten, Math.max( 0, fltChunkLen2 - fltSkip ));
}
fltFramesRead += fltChunkLen;
fltFramesWritten += Math.max( 0, fltChunkLen2 - fltSkip );
if( fltSkip > 0 ) {
fltSkip = Math.max( 0, fltSkip - fltChunkLen2 );
}
} // until framesWritten == outLength
// .... check running ....
if( !threadRunning ) break topLevel;
} // if( pr.intg[ PR_FILTERTYPE ] != FILTER_NONE )
// =================================================
// =============== writing out chunk ===============
// =================================================
//if( x == 51 && y == 23 ) {
// Debug.view( inBuf[ 0 ], 0, 1000, "Flt x = " + x + "; y = " + y, true, false );
//}
pWinSize = new Param( AudioFileDescr.samplesToMillis( outStream, winSize ), Param.ABS_MS );
i1 = Math.min( winSize, (int) (AudioFileDescr.millisToSamples( outStream, Param.transform( pr.para[ PR_ATTACK ], Param.ABS_MS, pWinSize, null ).value) + 0.5) );
if( i1 != atkLen ) {
atkLen = i1;
atkWin = Filter.createWindow( atkLen, Filter.WIN_HANNING );
Util.reverse( atkWin, 0, atkLen );
}
i1 = Math.min( winSize - atkLen, (int) (AudioFileDescr.millisToSamples( outStream, Param.transform( pr.para[ PR_RELEASE ], Param.ABS_MS, pWinSize, null ).value) + 0.5) );
if( i1 != rlsLen ) {
rlsLen = i1;
rlsWin = Filter.createWindow( rlsLen, Filter.WIN_HANNING );
}
// apply envelope
Util.mult( atkWin, 0, inBuf, 0, atkLen );
Util.mult( rlsWin, Math.max( 0, rlsLen - chunkLen ),
inBuf, Math.max( 0, chunkLen - rlsLen ),
Math.min( rlsLen, chunkLen ));
//if( x == 51 && y == 23 ) {
// Debug.view( inBuf[ 0 ], 0, 1000, "Out x = " + x + "; y = " + y, true, false );
//}
// apply gain
chunkGain = gain * (float) Math.min( maxBoost,
(Util.linexp( brightness, 0.0, 1.0, noiseFloor, 1.0 ) / Math.sqrt( bestRMS / (numSteps * numRMS) )));
//if( x != 8 ) chunkGain = 0.0f;
Util.mult( inBuf, 0, chunkLen, chunkGain );
outOff = Math.max( 0, (long) (x * framesPerPixel + ((rnd.nextDouble() * 2 - 1) * timeJitter * framesPerPixel) + 0.5) );
if( tmpF.getFrameNum() < outOff ) {
tmpF.setFrameNum( outOff );
}
tmpF.seekFrame( outOff );
chunkLen2 = (int) Math.min( chunkLen, tmpF.getFrameNum() - outOff );
if( chunkLen2 > 0 ) {
tmpF.readFrames( mixBuf, 0, chunkLen2 );
Util.add( mixBuf, 0, inBuf, 0, chunkLen2 );
tmpF.seekFrame( outOff );
}
tmpF.writeFrames( inBuf, 0, chunkLen );
progOff += inBufSize;
// .... progress ....
setProgression( (float) progOff / (float) progLen );
} // for y
// .... check running ....
if( !threadRunning ) break topLevel;
} // for x
inMatF.close();
inMatF = null;
// adjust gain
tmpF.seekFrame( 0 );
for( long framesRead = 0; threadRunning && (framesRead < tmpF.getFrameNum()); ) {
chunkLen = (int) Math.min( inBufSize, tmpF.getFrameNum() - framesRead );
tmpF.readFrames( inBuf, 0, chunkLen );
maxAmp = Math.max( maxAmp, Util.maxAbs( inBuf, 0, chunkLen ));
framesRead += chunkLen;
}
// .... check running ....
if( !threadRunning ) break topLevel;
if( pr.intg[ PR_GAINTYPE ] == GAIN_UNITY ) {
gain = (float) (Param.transform( pr.para[ PR_GAIN ], Param.ABS_AMP,
new Param( 1.0 / maxAmp, Param.ABS_AMP ), null )).value;
} else {
gain = 1.0f;
}
normalizeAudioFile( tmpF, outF, inBuf, gain, 1.0f );
deleteTempFile( tmpF );
// .... check running ....
if( !threadRunning ) break topLevel;
// ---- Finish ----
outF.close();
outF = null;
// inform about clipping/ low level
maxAmp *= gain;
handleClipping( maxAmp );
}
catch( IOException e1 ) {
setError( e1 );
}
catch( OutOfMemoryError e2 ) {
setError( new Exception( ERR_MEMORY ));
}
// ---- cleanup (topLevel) ----
if( outF != null ) outF.cleanUp();
if( inMatF != null ) inMatF.cleanUp();
} // process()
// -------- private methods --------
protected void reflectPropertyChanges()
{
super.reflectPropertyChanges();
Component c;
c = gui.getItemObj( GG_TIMEOVERLAP );
if( c != null ) {
c.setEnabled( !pr.bool[ PR_READMARKERS ]);
}
}
}