/* * SundayDlg.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 */ package de.sciss.fscape.gui; import de.sciss.fscape.io.FloatFile; 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.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.IOUtil; import javax.swing.*; import java.awt.*; import java.io.EOFException; import java.io.File; import java.io.IOException; /** * Something I tried out on a Sunday, * can't remember what it was. */ public class SundayDlg extends ModulePanel { // -------- private variables -------- // Properties (defaults) private static final int PR_INPUTFILE = 0; // pr.text private static final int PR_OUTPUTFILE = 1; 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_WINDOW = 3; private static final int PR_OVERLAP = 4; private static final int PR_GAIN = 0; // pr.para private static final int PR_CALCLEN = 1; private static final int PR_STEPSIZE = 2; private static final int PR_LPORDER = 3; private static final int PR_RESIDUAL = 0; // pr.bool private static final String PRN_INPUTFILE = "InputFile"; private static final String PRN_OUTPUTFILE = "OutputFile"; private static final String PRN_OUTPUTTYPE = "OutputType"; private static final String PRN_OUTPUTRES = "OutputReso"; private static final String PRN_CALCLEN = "CalcLen"; private static final String PRN_STEPSIZE = "StepSize"; private static final String PRN_LPORDER = "LPOrder"; private static final String PRN_RESIDUAL = "Residual"; private static final String PRN_WINDOW = "Window"; private static final String PRN_OVERLAP = "Overlap"; private static final String prText[] = { "", "" }; private static final String prTextName[] = { PRN_INPUTFILE, PRN_OUTPUTFILE }; private static final int prIntg[] = { 0, 0, GAIN_UNITY, Filter.WIN_HANNING, 2 }; private static final String prIntgName[] = { PRN_OUTPUTTYPE, PRN_OUTPUTRES, PRN_GAINTYPE, PRN_WINDOW, PRN_OVERLAP }; private static final Param prPara[] = { null, null, null, null }; private static final String prParaName[] = { PRN_GAIN, PRN_CALCLEN, PRN_STEPSIZE, PRN_LPORDER }; private static final boolean prBool[] = { true }; private static final String prBoolName[] = { PRN_RESIDUAL }; private static final int GG_INPUTFILE = GG_OFF_PATHFIELD + PR_INPUTFILE; private static final int GG_OUTPUTFILE = GG_OFF_PATHFIELD + PR_OUTPUTFILE; 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_WINDOW = GG_OFF_CHOICE + PR_WINDOW; private static final int GG_OVERLAP = GG_OFF_CHOICE + PR_OVERLAP; private static final int GG_GAIN = GG_OFF_PARAMFIELD + PR_GAIN; private static final int GG_CALCLEN = GG_OFF_PARAMFIELD + PR_CALCLEN; private static final int GG_STEPSIZE = GG_OFF_PARAMFIELD + PR_STEPSIZE; private static final int GG_LPORDER = GG_OFF_PARAMFIELD + PR_LPORDER; private static final int GG_RESIDUAL = GG_OFF_CHECKBOX + PR_RESIDUAL; private static PropertyArray static_pr = null; private static Presets static_presets = null; // -------- public methods -------- /** * !! setVisible() bleibt dem Aufrufer ueberlassen */ public SundayDlg() { super( "Sunday" ); 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_CALCLEN ] = new Param( 32.0, Param.ABS_MS ); static_pr.para[ PR_STEPSIZE ] = new Param( 8.0, Param.ABS_MS ); static_pr.para[ PR_LPORDER ] = new Param( 10.0, Param.NONE ); 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 -------- GridBagConstraints con; PathField ggInputFile, ggOutputFile; Component[] ggGain; PathField[] ggInputs; ParamField ggCalcLen, ggStepSize, ggLPOrder; JCheckBox ggResidual; JComboBox ggWindow, ggOverlap; String[] winNames; gui = new GUISupport(); con = gui.getGridBagConstraints(); con.insets = new Insets( 1, 2, 1, 2 ); // -------- Input-Gadgets -------- con.fill = GridBagConstraints.BOTH; con.gridwidth = GridBagConstraints.REMAINDER; gui.addLabel( new GroupLabel( "Waveform I/O", GroupLabel.ORIENT_HORIZONTAL, GroupLabel.BRACE_NONE )); ggInputFile = new PathField( PathField.TYPE_INPUTFILE + PathField.TYPE_FORMATFIELD, "Select input file" ); ggInputFile.handleTypes( GenericFile.TYPES_SOUND ); con.gridwidth = 1; con.weightx = 0.1; gui.addLabel( new JLabel( "Input file", SwingConstants.RIGHT )); con.gridwidth = GridBagConstraints.REMAINDER; con.weightx = 0.9; gui.addPathField( ggInputFile, GG_INPUTFILE, null ); ggOutputFile = new PathField( PathField.TYPE_OUTPUTFILE + PathField.TYPE_FORMATFIELD + PathField.TYPE_RESFIELD, "Select output file" ); ggOutputFile.handleTypes( GenericFile.TYPES_SOUND ); ggInputs = new PathField[ 1 ]; ggInputs[ 0 ] = ggInputFile; ggOutputFile.deriveFrom( ggInputs, "$D0$F0Sun$E" ); con.gridwidth = 1; con.weightx = 0.1; gui.addLabel( new JLabel( "Output file", 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, null ); // -------- Settings-Gadgets -------- con.fill = GridBagConstraints.BOTH; con.gridwidth = GridBagConstraints.REMAINDER; gui.addLabel( new GroupLabel( "LP Settings", GroupLabel.ORIENT_HORIZONTAL, GroupLabel.BRACE_NONE )); ggCalcLen = new ParamField( Constants.spaces[ Constants.absMsSpace ]); con.weightx = 0.1; con.gridwidth = 1; gui.addLabel( new JLabel( "Analysis Size", SwingConstants.RIGHT )); con.weightx = 0.4; gui.addParamField( ggCalcLen, GG_CALCLEN, null ); ggLPOrder = new ParamField( new ParamSpace( 2.0, 100000.0, 1.0, Param.NONE )); con.weightx = 0.1; gui.addLabel( new JLabel( "LP Order", SwingConstants.RIGHT )); con.weightx = 0.4; con.gridwidth = GridBagConstraints.REMAINDER; gui.addParamField( ggLPOrder, GG_LPORDER, null ); ggStepSize = new ParamField( Constants.spaces[ Constants.absMsSpace ]); con.weightx = 0.1; con.gridwidth = 1; gui.addLabel( new JLabel( "Synthesis Size", SwingConstants.RIGHT )); con.weightx = 0.4; gui.addParamField( ggStepSize, GG_STEPSIZE, null ); winNames = Filter.getWindowNames(); ggWindow = new JComboBox(); for( int i = 0; i < winNames.length; i++ ) { ggWindow.addItem( winNames[ i ]); } con.weightx = 0.1; gui.addLabel( new JLabel( "Window", SwingConstants.RIGHT )); con.gridwidth = GridBagConstraints.REMAINDER; con.weightx = 0.4; gui.addChoice( ggWindow, GG_WINDOW, null ); ggOverlap = new JComboBox(); for( int i = 0; i < 5; i++ ) { ggOverlap.addItem( "1/"+(1 << i) ); } con.weightx = 0.1; con.gridwidth = 1; gui.addLabel( new JLabel( "Window Step", SwingConstants.RIGHT )); con.weightx = 0.4; gui.addChoice( ggOverlap, GG_OVERLAP, null ); ggResidual = new JCheckBox(); con.weightx = 0.1; gui.addLabel( new JLabel( "Residual", SwingConstants.RIGHT )); con.gridwidth = GridBagConstraints.REMAINDER; con.weightx = 0.4; gui.addCheckbox( ggResidual, GG_RESIDUAL, null ); 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() { int i, j, k; int len, ch; long progOff, progLen; double d1; float f1; // io AudioFile inF = null; AudioFile outF = null; AudioFileDescr inStream = null; AudioFileDescr outStream = null; FloatFile[] floatF = null; File tempFile[] = null; float[][] inBuf, outBuf; float[] convBuf1, convBuf2; // Synthesize float gain = 1.0f; // gain abs amp Param ampRef = new Param( 1.0, Param.ABS_AMP ); // transform-Referenz // Smp Init int inLength, inChanNum; int framesRead, framesWritten; float maxAmp = 0.0f; PathField ggOutput; int bufSize, bufSizeH, readOff; double pow; topLevel: try { // ---- open input, output; init ---- // input inF = AudioFile.openAsRead( new File( pr.text[ PR_INPUTFILE ])); inStream = inF.getDescr(); inChanNum = inStream.channels; inLength = (int) inStream.length; // this helps to prevent errors from empty files! if( (inLength * inChanNum) < 1 ) throw new EOFException( ERR_EMPTY ); // .... check running .... if( !threadRunning ) break topLevel; // output ggOutput = (PathField) gui.getItemObj( GG_OUTPUTFILE ); if( ggOutput == null ) throw new IOException( ERR_MISSINGPROP ); outStream = new AudioFileDescr( inStream ); ggOutput.fillStream( outStream ); outF = AudioFile.openAsWrite( outStream ); // .... check running .... if( !threadRunning ) break topLevel; bufSizeH = 64; bufSize = bufSizeH << 1; pow = 1.0 / (bufSizeH - 1); inBuf = new float[ inChanNum ][ bufSize ]; outBuf = new float[ inChanNum ][ bufSizeH ]; Util.clear( inBuf ); progOff = 0; progLen = (long) inLength * 3; // normalization requires temp files if( pr.intg[ PR_GAINTYPE ] == GAIN_UNITY ) { tempFile = new File[ inChanNum ]; floatF = new FloatFile[ inChanNum ]; for( ch = 0; ch < inChanNum; ch++ ) { // first zero them because an exception might be thrown tempFile[ ch ] = null; floatF[ ch ] = null; } for( ch = 0; ch < inChanNum; ch++ ) { tempFile[ ch ] = IOUtil.createTempFile(); floatF[ ch ] = new FloatFile( tempFile[ ch ], GenericFile.MODE_OUTPUT ); } progLen += inLength; } else { gain = (float) (Param.transform( pr.para[ PR_GAIN ], Param.ABS_AMP, ampRef, null )).value; } // .... check running .... if( !threadRunning ) break topLevel; // =================== CORE =================== framesRead = 0; framesWritten = 0; readOff = 0; while( threadRunning && (framesWritten < inLength) ) { // ---- get input ---- for( ch = 0; ch < inChanNum; ch++ ) { System.arraycopy( inBuf[ch], bufSizeH, inBuf[ch], 0, bufSizeH ); } len = Math.min( bufSize - readOff, inLength - framesRead ); inF.readFrames( inBuf, readOff, len ); if( len + readOff < bufSize ) { for( ch = 0; ch < inChanNum; ch++ ) { convBuf1 = inBuf[ ch ]; for( i = readOff + len; i < bufSize; ) { convBuf1[ i++ ] = 0.0f; } } } progOff += len; framesRead += len; // .... progress .... setProgression( (float) progOff / (float) progLen ); // .... check running .... if( !threadRunning ) break topLevel; // ---- process ---- for( ch = 0; ch < inChanNum; ch++ ) { convBuf1 = inBuf[ ch ]; convBuf2 = outBuf[ ch ]; for( j = 0; j < bufSizeH; j++ ) { d1 = convBuf1[j]; for( i = j+1, k = bufSizeH-1; k > 0; i++, k-- ) { // d1 *= Math.pow( convBuf1[i], pow ); // d1 *= 1.0 - Math.abs( convBuf1[i]); d1 *= convBuf1[i]; } // convBuf2[j] = (float) d1; // Math.pow( d1, pow ); convBuf2[j] = (float) Math.pow( d1, pow ); } } progOff += len; // .... progress .... setProgression( (float) progOff / (float) progLen ); // .... check running .... if( !threadRunning ) break topLevel; // ---- save output ---- len = Math.min( bufSizeH, inLength - framesWritten ); if( floatF != null ) { for( ch = 0; ch < inChanNum; ch++ ) { convBuf1 = outBuf[ ch ]; for( i = 0; i < len; i++ ) { // measure max amp f1 = Math.abs( convBuf1[ i ]); if( f1 > maxAmp ) { maxAmp = f1; } } floatF[ ch ].writeFloats( convBuf1, 0, len ); } } else { // i.e. abs gain for( ch = 0; ch < inChanNum; ch++ ) { convBuf1 = outBuf[ ch ]; for( i = 0; i < len; i++ ) { // measure max amp + adjust gain f1 = Math.abs( convBuf1[ i ]); convBuf1[ i ] *= gain; if( f1 > maxAmp ) { maxAmp = f1; } } } outF.writeFrames( outBuf, 0, len ); } framesWritten += len; progOff += len; // .... progress .... setProgression( (float) progOff / (float) progLen ); readOff = bufSizeH; } // while framesWritten < outLength // .... check running .... if( !threadRunning ) break topLevel; // ---- normalize output ---- inF.close(); inF = null; // sound file 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; normalizeAudioFile( floatF, outF, inBuf, gain, 1.0f ); for( ch = 0; ch < inChanNum; ch++ ) { floatF[ ch ].cleanUp(); floatF[ ch ] = null; tempFile[ ch ].delete(); tempFile[ ch ] = null; } } // .... check running .... if( !threadRunning ) break topLevel; outF.close(); outF = null; // inform about clipping/ low level maxAmp *= gain; handleClipping( maxAmp ); } catch( IOException e1 ) { setError( e1 ); } catch( OutOfMemoryError e2 ) { inStream = null; outStream = null; inBuf = null; outBuf = null; convBuf1 = null; convBuf2 = null; System.gc(); setError( new Exception( ERR_MEMORY )); } // ---- cleanup (topLevel) ---- if( outF != null ) { outF.cleanUp(); } if( inF != null ) { inF.cleanUp(); } } // process() }