/* * UnaryOpDlg.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: * 09-Jan-05 correct offset unit switch, correct offset reference */ 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.Param; import de.sciss.fscape.util.ParamSpace; import de.sciss.fscape.util.Util; import de.sciss.gui.PathEvent; import de.sciss.gui.PathListener; import de.sciss.io.AudioFile; import de.sciss.io.AudioFileDescr; import de.sciss.io.IOUtil; import javax.swing.*; import java.awt.*; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.io.File; import java.io.IOException; /** * Processing module for algebraic * modification of a sound files on * a sample-by-sample basis. */ public class UnaryOpDlg extends ModulePanel { // -------- public variables -------- // -------- private variables -------- // Properties (defaults) private static final int PR_REINPUTFILE = 0; // pr.text private static final int PR_IMINPUTFILE = 1; private static final int PR_REOUTPUTFILE = 2; private static final int PR_IMOUTPUTFILE = 3; private static final int PR_OUTPUTTYPE = 0; // pr.intg private static final int PR_OUTPUTRES = 1; private static final int PR_OPERATOR = 2; private static final int PR_GAINTYPE = 3; // private static final int PR_INGAINTYPE = 4; private static final int PR_GAIN = 0; // pr.para private static final int PR_INPUTGAIN = 1; private static final int PR_OFFSET = 2; private static final int PR_LENGTH = 3; private static final int PR_DRYMIX = 4; private static final int PR_WETMIX = 5; private static final int PR_HASIMINPUT = 0; // pr.bool private static final int PR_HASIMOUTPUT = 1; private static final int PR_RECTIFY = 2; private static final int PR_INVERT = 3; private static final int PR_DRYINVERT = 4; private static final int PR_REVERSE = 5; private static final int OP_NONE = 0; private static final int OP_SIN = 1; private static final int OP_SQR = 2; private static final int OP_SQRT = 3; private static final int OP_LOG = 4; private static final int OP_EXP = 5; private static final int OP_RECT2POLARW = 6; private static final int OP_RECT2POLAR = 7; private static final int OP_POLAR2RECT = 8; private static final int OP_NOT = 9; private static final String OPNAMES[] = { "Untouched", "Sin(x)", "Square", "Square root", "Log(x)", "Exp(x)", "Rect->Polar (wrapped)", "Rect->Polar", "Polar->Rect", "NOT" }; private static final String PRN_REINPUTFILE = "ReInFile"; private static final String PRN_IMINPUTFILE = "ImInFile"; private static final String PRN_REOUTPUTFILE = "ReOutFile"; private static final String PRN_IMOUTPUTFILE = "ImOutFile"; private static final String PRN_OUTPUTTYPE = "OutputType"; private static final String PRN_OUTPUTRES = "OutputReso"; private static final String PRN_OPERATOR = "Operator"; private static final String PRN_INGAINTYPE = "InGainType"; private static final String PRN_INPUTGAIN = "InGain"; private static final String PRN_OFFSET = "Offset"; private static final String PRN_LENGTH = "Length"; private static final String PRN_DRYMIX = "DryMix"; private static final String PRN_WETMIX = "WetMix"; private static final String PRN_HASIMINPUT = "HasImInput"; private static final String PRN_HASIMOUTPUT = "HasImOutput"; private static final String PRN_RECTIFY = "Rectify"; private static final String PRN_INVERT = "Invert"; private static final String PRN_DRYINVERT = "DryInvert"; private static final String PRN_REVERSE = "Reverse"; private static final String prText[] = { "", "", "", "" }; private static final String prTextName[] = { PRN_REINPUTFILE, PRN_IMINPUTFILE, PRN_REOUTPUTFILE, PRN_IMOUTPUTFILE }; private static final int prIntg[] = { 0, 0, OP_NONE, GAIN_UNITY, GAIN_ABSOLUTE }; private static final String prIntgName[] = { PRN_OUTPUTTYPE, PRN_OUTPUTRES, PRN_OPERATOR, PRN_GAINTYPE, PRN_INGAINTYPE }; private static final Param prPara[] = { null, null, null, null, null, null }; private static final String prParaName[] = { PRN_GAIN, PRN_INPUTGAIN, PRN_OFFSET, PRN_LENGTH, PRN_DRYMIX, PRN_WETMIX }; private static final boolean prBool[] = { false, false, false, false, false, false }; private static final String prBoolName[] = { PRN_HASIMINPUT, PRN_HASIMOUTPUT, PRN_RECTIFY, PRN_INVERT, PRN_DRYINVERT, PRN_REVERSE }; private static final int GG_REINPUTFILE = GG_OFF_PATHFIELD + PR_REINPUTFILE; private static final int GG_IMINPUTFILE = GG_OFF_PATHFIELD + PR_IMINPUTFILE; private static final int GG_REOUTPUTFILE = GG_OFF_PATHFIELD + PR_REOUTPUTFILE; private static final int GG_IMOUTPUTFILE = GG_OFF_PATHFIELD + PR_IMOUTPUTFILE; 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_OPERATOR = GG_OFF_CHOICE + PR_OPERATOR; private static final int GG_GAINTYPE = GG_OFF_CHOICE + PR_GAINTYPE; // private static final int GG_INGAINTYPE = GG_OFF_CHOICE + PR_INGAINTYPE; private static final int GG_GAIN = GG_OFF_PARAMFIELD + PR_GAIN; private static final int GG_INPUTGAIN = GG_OFF_PARAMFIELD + PR_INPUTGAIN; private static final int GG_OFFSET = GG_OFF_PARAMFIELD + PR_OFFSET; private static final int GG_LENGTH = GG_OFF_PARAMFIELD + PR_LENGTH; private static final int GG_DRYMIX = GG_OFF_PARAMFIELD + PR_DRYMIX; private static final int GG_WETMIX = GG_OFF_PARAMFIELD + PR_WETMIX; private static final int GG_HASIMINPUT = GG_OFF_CHECKBOX + PR_HASIMINPUT; private static final int GG_HASIMOUTPUT = GG_OFF_CHECKBOX + PR_HASIMOUTPUT; private static final int GG_RECTIFY = GG_OFF_CHECKBOX + PR_RECTIFY; private static final int GG_INVERT = GG_OFF_CHECKBOX + PR_INVERT; private static final int GG_DRYINVERT = GG_OFF_CHECKBOX + PR_DRYINVERT; private static final int GG_REVERSE = GG_OFF_CHECKBOX + PR_REVERSE; private static PropertyArray static_pr = null; private static Presets static_presets = null; private static final String ERR_NOTCOMPLEX = "This operation requires complex input"; // -------- public methods -------- /** * !! setVisible() bleibt dem Aufrufer ueberlassen */ public UnaryOpDlg() { super( "Unary Operator" ); 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.para = prPara; static_pr.para[ PR_INPUTGAIN ] = new Param( 0.0, Param.DECIBEL_AMP ); static_pr.para[ PR_OFFSET ] = new Param( 0.0, Param.ABS_MS ); static_pr.para[ PR_LENGTH ] = new Param( 100.0, Param.FACTOR_TIME ); static_pr.para[ PR_DRYMIX ] = new Param( 0.0, Param.FACTOR_AMP ); static_pr.para[ PR_WETMIX ] = new Param( 100.0, Param.FACTOR_AMP ); static_pr.paraName = prParaName; static_pr.bool = prBool; static_pr.boolName = prBoolName; // 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 ggImInputFile, ggReInputFile, ggReOutputFile, ggImOutputFile; ParamField ggInputGain, ggOffset, ggLength, ggDryMix, ggWetMix; JComboBox ggOperator; JCheckBox ggHasImInput, ggHasImOutput, ggRectify, ggInvert, ggDryInvert, ggReverse; PathField[] ggParent1, ggParent2; Component[] ggGain; ParamSpace[] spcOffset, spcLength; int anchor; gui = new GUISupport(); con = gui.getGridBagConstraints(); con.insets = new Insets( 1, 2, 1, 2 ); ItemListener il = new ItemListener() { public void itemStateChanged( ItemEvent e ) { int ID = gui.getItemID( e ); switch( ID ) { case GG_HASIMINPUT: case GG_HASIMOUTPUT: pr.bool[ ID - GG_OFF_CHECKBOX ] = ((JCheckBox) e.getSource()).isSelected(); reflectPropertyChanges(); break; } } }; PathListener pathL = new PathListener() { public void pathChanged( PathEvent e ) { int ID = gui.getItemID( e ); switch( ID ) { case PR_REINPUTFILE: setInput( ((PathField) e.getSource()).getPath().getPath() ); break; } } }; // -------- Input-Gadgets -------- spcOffset = new ParamSpace[ 3 ]; spcOffset[0] = new ParamSpace( -36000000.0, 36000000.0, 0.1, Param.ABS_MS ); // allow negative offset spcOffset[1] = new ParamSpace( -240000.0, 240000.0, 0.001, Param.ABS_BEATS ); spcOffset[2] = new ParamSpace( -100.0, 100.0, 0.01, Param.FACTOR_TIME ); // spcOffset[0] = Constants.spaces[ Constants.absMsSpace ]; // spcOffset[1] = Constants.spaces[ Constants.absBeatsSpace ]; // spcOffset[2] = Constants.spaces[ Constants.offsetTimeSpace ]; spcLength = new ParamSpace[ 4 ]; spcLength[0] = Constants.spaces[ Constants.absMsSpace ]; spcLength[1] = Constants.spaces[ Constants.absBeatsSpace ]; spcLength[2] = Constants.spaces[ Constants.offsetTimeSpace ]; spcLength[3] = Constants.spaces[ Constants.factorTimeSpace ]; con.fill = GridBagConstraints.BOTH; con.gridwidth = GridBagConstraints.REMAINDER; gui.addLabel( new GroupLabel( "Input file", GroupLabel.ORIENT_HORIZONTAL, GroupLabel.BRACE_NONE )); con.fill = GridBagConstraints.HORIZONTAL; ggReInputFile = new PathField( PathField.TYPE_INPUTFILE + PathField.TYPE_FORMATFIELD, "Select real part of input" ); ggReInputFile.handleTypes( GenericFile.TYPES_SOUND ); con.gridwidth = 1; con.weightx = 0.1; gui.addLabel( new JLabel( "Input [Real]", SwingConstants.RIGHT )); con.gridwidth = 2; con.weightx = 3.0; gui.addPathField( ggReInputFile, GG_REINPUTFILE, pathL ); ggOffset = new ParamField( spcOffset ); con.weightx = 0.1; con.gridwidth = 1; gui.addLabel( new JLabel( "Offset", SwingConstants.RIGHT )); con.weightx = 0.4; con.gridwidth = GridBagConstraints.REMAINDER; gui.addParamField( ggOffset, GG_OFFSET, null ); ggImInputFile = new PathField( PathField.TYPE_INPUTFILE + PathField.TYPE_FORMATFIELD, "Select imaginary part of input" ); ggImInputFile.handleTypes( GenericFile.TYPES_SOUND ); ggHasImInput = new JCheckBox( "Input [Imaginary]" ); con.gridwidth = 1; con.weightx = 0.1; anchor = con.anchor; con.anchor = GridBagConstraints.EAST; gui.addCheckbox( ggHasImInput, GG_HASIMINPUT, il ); con.anchor = anchor; con.weightx = 3.0; con.gridwidth = 2; gui.addPathField( ggImInputFile, GG_IMINPUTFILE, pathL ); ggLength = new ParamField( spcLength ); con.weightx = 0.1; con.gridwidth = 1; gui.addLabel( new JLabel( "Length", SwingConstants.RIGHT )); con.weightx = 0.4; con.gridwidth = GridBagConstraints.REMAINDER; gui.addParamField( ggLength, GG_LENGTH, null ); ggParent1 = new PathField[ 1 ]; ggParent1[ 0 ] = ggReInputFile; ggParent2 = new PathField[ 1 ]; ggParent2[ 0 ] = ggReInputFile; ggImInputFile.deriveFrom( ggParent2, "$D0$F0i$X0" ); ggInputGain = new ParamField( Constants.spaces[ Constants.decibelAmpSpace ]); con.gridwidth = 1; con.weightx = 0.1; gui.addLabel( new JLabel( "Drive", SwingConstants.RIGHT )); con.weightx = 0.4; gui.addParamField( ggInputGain, GG_INPUTGAIN, null ); con.weightx = 0.1; con.gridwidth = 1; gui.addLabel( new JLabel( "" )); ggRectify = new JCheckBox( "Rectify" ); con.gridwidth = 1; con.weightx = 0.4; gui.addCheckbox( ggRectify, GG_RECTIFY, il ); ggInvert = new JCheckBox( "Invert" ); gui.addCheckbox( ggInvert, GG_INVERT, il ); ggReverse = new JCheckBox( "Reverse" ); con.gridwidth = GridBagConstraints.REMAINDER; gui.addCheckbox( ggReverse, GG_REVERSE, il ); // -------- Output-Gadgets -------- gui.addLabel( new GroupLabel( "Output", GroupLabel.ORIENT_HORIZONTAL, GroupLabel.BRACE_NONE )); ggReOutputFile = new PathField( PathField.TYPE_OUTPUTFILE + PathField.TYPE_FORMATFIELD + PathField.TYPE_RESFIELD, "Select output for real part" ); ggReOutputFile.handleTypes( GenericFile.TYPES_SOUND ); con.gridwidth = 1; con.weightx = 0.1; gui.addLabel( new JLabel( "File [Real]", SwingConstants.RIGHT )); con.gridwidth = GridBagConstraints.REMAINDER; con.weightx = 0.9; gui.addPathField( ggReOutputFile, GG_REOUTPUTFILE, pathL ); gui.registerGadget( ggReOutputFile.getTypeGadget(), GG_OUTPUTTYPE ); gui.registerGadget( ggReOutputFile.getResGadget(), GG_OUTPUTRES ); ggImOutputFile = new PathField( PathField.TYPE_OUTPUTFILE, "Select output for imaginary part" ); // ggImOutputFile.handleTypes( GenericFile.TYPES_SOUND ); ggHasImOutput = new JCheckBox( "File [Imaginary]" ); con.gridwidth = 1; con.weightx = 0.1; anchor = con.anchor; con.anchor = GridBagConstraints.EAST; gui.addCheckbox( ggHasImOutput, GG_HASIMOUTPUT, il ); con.anchor = anchor; con.gridwidth = GridBagConstraints.REMAINDER; con.weightx = 0.9; gui.addPathField( ggImOutputFile, GG_IMOUTPUTFILE, pathL ); ggParent2 = new PathField[ 1 ]; ggParent2[ 0 ] = ggReOutputFile; ggReOutputFile.deriveFrom( ggParent1, "$D0$F0Op$E" ); ggImOutputFile.deriveFrom( ggParent2, "$D0$F0i$X0" ); 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 ); // -------- Settings -------- gui.addLabel( new GroupLabel( "Operation", GroupLabel.ORIENT_HORIZONTAL, GroupLabel.BRACE_NONE )); ggOperator = new JComboBox(); for( int i = 0; i < OPNAMES.length; i++ ) { ggOperator.addItem( OPNAMES[ i ]); } con.gridwidth = 1; con.weightx = 0.1; gui.addLabel( new JLabel( "Operator", SwingConstants.RIGHT )); con.weightx = 0.4; gui.addChoice( ggOperator, GG_OPERATOR, il ); // con.weightx = 0.1; // gui.addLabel( new JLabel( "" )); ggDryMix = new ParamField( Constants.spaces[ Constants.ratioAmpSpace ]); gui.addLabel( new JLabel( "Dry mix", SwingConstants.RIGHT )); con.weightx = 0.4; con.gridwidth = 2; gui.addParamField( ggDryMix, GG_DRYMIX, null ); ggDryInvert = new JCheckBox( "Invert" ); con.weightx = 0.1; con.gridwidth = GridBagConstraints.REMAINDER; gui.addCheckbox( ggDryInvert, GG_DRYINVERT, il ); // con.gridwidth = 3; con.gridwidth = 2; gui.addLabel( new JLabel( "" )); ggWetMix = new ParamField( Constants.spaces[ Constants.ratioAmpSpace ]); con.weightx = 0.1; con.gridwidth = 1; gui.addLabel( new JLabel( "Wet mix", SwingConstants.RIGHT )); con.weightx = 0.4; con.gridwidth = 2; gui.addParamField( ggWetMix, GG_WETMIX, null ); con.weightx = 0.1; con.gridwidth = GridBagConstraints.REMAINDER; gui.addLabel( new JLabel( "" )); 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 -------- /** * Translation durchfuehren */ public void process() { int i, j, k; int ch, len; float f1; double d1, d2, d3, d4, d5; long progOff, progLen, lo; // io AudioFile reInF = null; AudioFile imInF = null; AudioFile reOutF = null; AudioFile imOutF = null; AudioFileDescr reInStream = null; AudioFileDescr imInStream = null; AudioFileDescr reOutStream = null; AudioFileDescr imOutStream = null; FloatFile reFloatF[] = null; FloatFile imFloatF[] = null; File reTempFile[] = null; File imTempFile[] = null; int outChanNum; float[][] reInBuf; // [ch][i] float[][] imInBuf; // [ch][i] float[][] reOutBuf = null; // [ch][i] float[][] imOutBuf = null; // [ch][i] float[] convBuf1, convBuf2; boolean complex; PathField ggOutput; // Synthesize Param ampRef = new Param( 1.0, Param.ABS_AMP ); // transform-Referenz float gain; // gain abs amp float dryGain, wetGain; float inGain; float maxAmp = 0.0f; Param peakGain; int inLength, inOff; int pre; int post; int length; int framesRead, framesWritten, outLength; boolean polarIn, polarOut; // phase unwrapping double[] phi; int[] wrap; double[] carry; Param lenRef; topLevel: try { complex = pr.bool[ PR_HASIMINPUT ] || pr.bool[ PR_HASIMOUTPUT ]; polarIn = pr.intg[ PR_OPERATOR ] == OP_POLAR2RECT; polarOut= pr.intg[ PR_OPERATOR ] == OP_RECT2POLAR; if( (polarIn || polarOut) && !complex ) throw new IOException( ERR_NOTCOMPLEX ); // ---- open input ---- reInF = AudioFile.openAsRead( new File( pr.text[ PR_REINPUTFILE ])); reInStream = reInF.getDescr(); inLength = (int) reInStream.length; reInBuf = new float[ reInStream.channels ][ 8192 ]; imInBuf = new float[ reInStream.channels ][ 8192 ]; if( pr.bool[ PR_HASIMINPUT ]) { imInF = AudioFile.openAsRead( new File( pr.text[ PR_IMINPUTFILE ])); imInStream = imInF.getDescr(); if( imInStream.channels != reInStream.channels ) throw new IOException( ERR_COMPLEX ); inLength = (int) Math.min( inLength, imInStream.length ); } lenRef = new Param( AudioFileDescr.samplesToMillis( reInStream, inLength ), Param.ABS_MS ); d1 = AudioFileDescr.millisToSamples( reInStream, (Param.transform( pr.para[ PR_OFFSET ], Param.ABS_MS, lenRef, null ).value)); j = (int) (d1 >= 0.0 ? (d1 + 0.5) : (d1 - 0.5)); // correct rounding for negative values! length = (int) (AudioFileDescr.millisToSamples( reInStream, (Param.transform( pr.para[ PR_LENGTH ], Param.ABS_MS, lenRef, null )).value) + 0.5); // System.err.println( "offset = "+j ); if( j >= 0 ) { inOff = Math.min( j, inLength ); if( !pr.bool[ PR_REVERSE ]) { reInF.seekFrame( inOff ); if( pr.bool[ PR_HASIMINPUT ]) { imInF.seekFrame( inOff ); } } inLength -= inOff; pre = 0; } else { inOff = 0; pre = Math.min( -j, length ); } inLength = Math.min( inLength, length - pre ); post = length - pre - inLength; if( pr.bool[ PR_REVERSE ]) { i = pre; pre = post; post = i; inOff += inLength; } // .... check running .... if( !threadRunning ) break topLevel; // for( op = 0; op < 2; op++ ) { // System.out.println( op +": pre "+pre[op]+" / len "+inLength[op]+" / post "+post[op] ); // } // System.out.println( "tot "+length[0]); outLength = length; outChanNum = reInStream.channels; // ---- open output ---- ggOutput = (PathField) gui.getItemObj( GG_REOUTPUTFILE ); if( ggOutput == null ) throw new IOException( ERR_MISSINGPROP ); reOutStream = new AudioFileDescr( reInStream ); ggOutput.fillStream( reOutStream ); reOutStream.channels = outChanNum; // well, more sophisticated code would // move and truncate the markers... if( (pre == 0) /* && (post == 0) */ ) { reInF.readMarkers(); reOutStream.setProperty( AudioFileDescr.KEY_MARKERS, reInStream.getProperty( AudioFileDescr.KEY_MARKERS )); } reOutF = AudioFile.openAsWrite( reOutStream ); reOutBuf = new float[ outChanNum ][ 8192 ]; imOutBuf = new float[ outChanNum ][ 8192 ]; if( pr.bool[ PR_HASIMOUTPUT ]) { imOutStream = new AudioFileDescr( reInStream ); ggOutput.fillStream( imOutStream ); imOutStream.channels = outChanNum; imOutStream.file = new File( pr.text[ PR_IMOUTPUTFILE ]); imOutF = AudioFile.openAsWrite( imOutStream ); } // .... check running .... if( !threadRunning ) break topLevel; // ---- Further inits ---- phi = new double[ outChanNum ]; wrap = new int[ outChanNum ]; carry = new double[ outChanNum ]; for( ch = 0; ch < outChanNum; ch++ ) { phi[ ch ] = 0.0; wrap[ ch ] = 0; carry[ ch ] = Double.NEGATIVE_INFINITY; } progOff = 0; // read, transform, write progLen = (long) outLength * 3; wetGain = (float) (Param.transform( pr.para[ PR_WETMIX ], Param.ABS_AMP, ampRef, null )).value; dryGain = (float) (Param.transform( pr.para[ PR_DRYMIX ], Param.ABS_AMP, ampRef, null )).value; if( pr.bool[ PR_DRYINVERT ]) { dryGain = -dryGain; } inGain = (float) (Param.transform( pr.para[ PR_INPUTGAIN ], Param.ABS_AMP, ampRef, null )).value; if( pr.bool[ PR_INVERT ]) { inGain = -inGain; } // normalization requires temp files if( pr.intg[ PR_GAINTYPE ] == GAIN_UNITY ) { reTempFile = new File[ outChanNum ]; reFloatF = new FloatFile[ outChanNum ]; for( ch = 0; ch < outChanNum; ch++ ) { // first zero them because an exception might be thrown reTempFile[ ch ] = null; reFloatF[ ch ] = null; } for( ch = 0; ch < outChanNum; ch++ ) { reTempFile[ ch ] = IOUtil.createTempFile(); reFloatF[ ch ] = new FloatFile( reTempFile[ ch ], GenericFile.MODE_OUTPUT ); } if( pr.bool[ PR_HASIMOUTPUT ]) { imTempFile = new File[ outChanNum ]; imFloatF = new FloatFile[ outChanNum ]; for( ch = 0; ch < outChanNum; ch++ ) { // first zero them because an exception might be thrown imTempFile[ ch ] = null; imFloatF[ ch ] = null; } for( ch = 0; ch < outChanNum; ch++ ) { imTempFile[ ch ] = IOUtil.createTempFile(); imFloatF[ ch ] = new FloatFile( imTempFile[ ch ], GenericFile.MODE_OUTPUT ); } } progLen += outLength; } else { gain = (float) (Param.transform( pr.para[ PR_GAIN ], Param.ABS_AMP, ampRef, null )).value; wetGain *= gain; dryGain *= gain; } // .... check running .... if( !threadRunning ) break topLevel; // ----==================== the real stuff ====================---- framesRead = 0; framesWritten = 0; while( threadRunning && (framesWritten < outLength) ) { // ---- choose chunk len ---- len = Math.min( 8192, outLength - framesWritten ); if( pre > 0 ) { len = Math.min( len, pre ); } else if( inLength > 0 ) { len = Math.min( len, inLength ); } else { len = Math.min( len, post ); } // ---- read input chunks ---- if( pre > 0 ) { Util.clear( reInBuf ); if( complex ) { Util.clear( imInBuf ); } pre -= len; } else if( inLength > 0 ) { if( pr.bool[ PR_REVERSE ]) { // ---- read reversed ---- reInF.seekFrame( inOff - framesRead - len ); reInF.readFrames( reInBuf, 0, len ); for( ch = 0; ch < reInStream.channels; ch++ ) { convBuf1 = reInBuf[ ch ]; for( i = 0, j = len - 1; i < j; i++, j-- ) { f1 = convBuf1[ j ]; convBuf1[ j ] = convBuf1[ i ]; convBuf1[ i ] = f1; } } if( pr.bool[ PR_HASIMINPUT ]) { imInF.seekFrame( inOff - framesRead - len ); imInF.readFrames( imInBuf, 0, len ); for( ch = 0; ch < imInStream.channels; ch++ ) { convBuf1 = imInBuf[ ch ]; for( i = 0, j = len - 1; i < j; i++, j-- ) { f1 = convBuf1[ j ]; convBuf1[ j ] = convBuf1[ i ]; convBuf1[ i ] = f1; } } } else if( complex ) { Util.clear( imInBuf ); } } else { // ---- read normal ---- reInF.readFrames( reInBuf, 0, len ); if( pr.bool[ PR_HASIMINPUT ]) { imInF.readFrames( imInBuf, 0, len ); } else if( complex ) { Util.clear( imInBuf ); } } inLength -= len; framesRead += len; } else { Util.clear( reInBuf ); if( complex ) { Util.clear( imInBuf ); } post -= len; } progOff += len; // .... progress .... setProgression( (float) progOff / (float) progLen ); // .... check running .... if( !threadRunning ) break topLevel; // ---- save dry signal ---- for( ch = 0; ch < outChanNum; ch++ ) { convBuf1 = reInBuf[ ch ]; convBuf2 = reOutBuf[ ch ]; for( i = 0; i < len; i++ ) { convBuf2[ i ] = convBuf1[ i ] * dryGain; } if( complex ) { convBuf1 = imInBuf[ ch ]; convBuf2 = imOutBuf[ ch ]; for( i = 0; i < len; i++ ) { convBuf2[ i ] = convBuf1[ i ] * dryGain; } } } // ---- rectify + apply input gain ---- for( ch = 0; ch < reInStream.channels; ch++ ) { convBuf1 = reInBuf[ ch ]; convBuf2 = imInBuf[ ch ]; // ---- rectify ---- if( pr.bool[ PR_RECTIFY ]) { if( complex ) { if( polarIn ) { for( i = 0; i < len; i++ ) { convBuf2[ i ] = 0.0f; } } else { for( i = 0; i < len; i++ ) { d1 = convBuf1[ i ]; d2 = convBuf2[ i ]; convBuf1[ i ] = (float) Math.sqrt( d1*d1 + d2*d2 ); convBuf2[ i ] = 0.0f; } } } else { for( i = 0; i < len; i++ ) { convBuf1[ i ] = Math.abs( convBuf1[ i ]); } } } // ---- apply input gain ---- Util.mult( convBuf1, 0, len, inGain ); if( complex & !polarIn ) { Util.mult( convBuf2, 0, len, inGain ); } } // ---- heart of the dragon ---- for( ch = 0; ch < outChanNum; ch++ ) { convBuf1 = reInBuf[ ch ]; convBuf2 = imInBuf[ ch ]; switch( pr.intg[ PR_OPERATOR ]) { case OP_NONE: // ================ None ================ for( i = 0; i < len; i++ ) { reOutBuf[ ch ][ i ] += wetGain * convBuf1[ i ]; } if( complex ) { for( i = 0; i < len; i++ ) { imOutBuf[ ch ][ i ] += wetGain * convBuf2[ i ]; } } break; case OP_SIN: // ================ Cosinus ================ if( complex ) { for( i = 0; i < len; i++ ) { reOutBuf[ ch ][ i ] += wetGain * (float) Math.sin( convBuf1[ i ] * Math.PI ); imOutBuf[ ch ][ i ] += wetGain * (float) Math.sin( convBuf2[ i ] * Math.PI ); } } else { for( i = 0; i < len; i++ ) { reOutBuf[ ch ][ i ] += wetGain * (float) Math.sin( convBuf1[ i ] * Math.PI ); } } break; case OP_SQR: // ================ Square ================ if( complex ) { for( i = 0; i < len; i++ ) { reOutBuf[ ch ][ i ] += wetGain * (convBuf1[i]*convBuf1[i] - convBuf2[i]*convBuf2[i]); imOutBuf[ ch ][ i ] -= wetGain * (convBuf1[i]*convBuf2[i]*2); } } else { for( i = 0; i < len; i++ ) { reOutBuf[ ch ][ i ] += wetGain * (convBuf1[i]*convBuf1[i]); } } break; case OP_SQRT: // ================ Square root ================ if( complex ) { d3 = phi[ ch ]; k = wrap[ ch ]; d4 = k * Constants.PI2; for( i = 0; i < len; i++ ) { d1 = wetGain * Math.pow( convBuf1[ i ] * convBuf1[ i ] + convBuf2[ i ] * convBuf2[ i ], 0.25 ); d2 = Math.atan2( convBuf2[i], convBuf1[i] ); if( d2 - d3 > Math.PI ) { k--; d4 = k * Constants.PI2; } else if( d3 - d2 > Math.PI ) { k++; d4 = k * Constants.PI2; } d2 += d4; d3 = d2; d2 /= 2; reOutBuf[ ch ][ i ] += (float) (d1 * Math.cos( d2 )); imOutBuf[ ch ][ i ] += (float) (d1 * Math.sin( d2 )); } phi[ ch ] = d3; wrap[ ch ] = k; } else { for( i = 0; i < len; i++ ) { f1 = convBuf1[ i ]; if( f1 > 0 ) { reOutBuf[ ch ][ i ] += wetGain * (float) Math.sqrt( f1 ); } // else undefiniert } } break; case OP_RECT2POLARW: // ================ Rect->Polar (wrapped) ================ for( i = 0; i < len; i++ ) { d1 = wetGain * Math.sqrt( convBuf1[ i ] * convBuf1[ i ] + convBuf2[ i ] * convBuf2[ i ]); d2 = Math.atan2( convBuf2[i], convBuf1[i] ); reOutBuf[ ch ][ i ] += (float) d1; imOutBuf[ ch ][ i ] += (float) d2; } break; case OP_RECT2POLAR: // ================ Rect->Polar ================ d3 = phi[ ch ]; k = wrap[ ch ]; d4 = k * Constants.PI2; for( i = 0; i < len; i++ ) { d1 = wetGain * Math.sqrt( convBuf1[ i ] * convBuf1[ i ] + convBuf2[ i ] * convBuf2[ i ]); d2 = Math.atan2( convBuf2[i], convBuf1[i] ); if( d2 - d3 > Math.PI ) { k--; d4 = k * Constants.PI2; } else if( d3 - d2 > Math.PI ) { k++; d4 = k * Constants.PI2; } d2 += d4; reOutBuf[ ch ][ i ] += (float) d1; imOutBuf[ ch ][ i ] += (float) d2; d3 = d2; } phi[ ch ] = d3; wrap[ ch ] = k; break; case OP_POLAR2RECT: // ================ Polar->Rect ================ for( i = 0; i < len; i++ ) { f1 = wetGain * convBuf1[ i ]; reOutBuf[ ch ][ i ] += f1 * (float) Math.cos( convBuf2[ i ]); imOutBuf[ ch ][ i ] += f1 * (float) Math.sin( convBuf2[ i ]); } break; case OP_LOG: // ================ Log ================ if( complex ) { d3 = phi[ ch ]; k = wrap[ ch ]; d4 = k * Constants.PI2; d5 = carry[ ch ]; for( i = 0; i < len; i++ ) { d1 = Math.sqrt( convBuf1[i] * convBuf1[i] + convBuf2[i] * convBuf2[i] ); d2 = Math.atan2( convBuf2[i], convBuf1[i] ); if( d2 - d3 > Math.PI ) { k--; d4 = k * Constants.PI2; } else if( d3 - d2 > Math.PI ) { k++; d4 = k * Constants.PI2; } if( d1 > 0.0 ) { d5 = Math.log( d1 ); } d2 += d4; reOutBuf[ ch ][ i ] += (float) d5; imOutBuf[ ch ][ i ] += (float) d2; d3 = d2; } phi[ ch ] = d3; wrap[ ch ] = k; carry[ ch ] = d5; } else { for( i = 0; i < len; i++ ) { f1 = convBuf1[ i ]; if( f1 > 0 ) { reOutBuf[ ch ][ i ] += wetGain * (float) Math.log( f1 ); } // else undefiniert } } break; case OP_EXP: // ================ Exp ================ if( complex ) { for( i = 0; i < len; i++ ) { d1 = wetGain * Math.exp( convBuf1[ i ]); reOutBuf[ ch ][ i ] += (float) (d1 * Math.cos( convBuf2[i] )); imOutBuf[ ch ][ i ] += (float) (d1 * Math.sin( convBuf2[i] )); } } else { for( i = 0; i < len; i++ ) { reOutBuf[ ch ][ i ] += wetGain * (float) Math.exp( convBuf1[ i ]); } } break; case OP_NOT: // ================ NOT ================ for( i = 0; i < len; i++ ) { lo = ~((long) (convBuf1[i] * 2147483647.0)); reOutBuf[ ch ][ i ] += wetGain * (float) ((lo & 0xFFFFFFFFL) / 2147483647.0); } if( complex ) { for( i = 0; i < len; i++ ) { lo = ~((long) (convBuf2[i] * 2147483647.0)); imOutBuf[ ch ][ i ] += wetGain * (float) ((lo & 0xFFFFFFFFL) / 2147483647.0); } } break; } } // for outChan progOff += len; // .... progress .... setProgression( (float) progOff / (float) progLen ); // .... check running .... if( !threadRunning ) break topLevel; // ---- write output chunk ---- if( reFloatF != null ) { for( ch = 0; ch < outChanNum; ch++ ) { reFloatF[ ch ].writeFloats( reOutBuf[ ch ], 0, len ); if( pr.bool[ PR_HASIMOUTPUT ]) { imFloatF[ ch ].writeFloats( imOutBuf[ ch ], 0, len ); } } } else { reOutF.writeFrames( reOutBuf, 0, len ); if( pr.bool[ PR_HASIMOUTPUT ]) { imOutF.writeFrames( imOutBuf, 0, len ); } } // check max amp for( ch = 0; ch < outChanNum; ch++ ) { convBuf1 = reOutBuf[ ch ]; for( i = 0; i < len; i++ ) { f1 = Math.abs( convBuf1[ i ]); if( f1 > maxAmp ) { maxAmp = f1; } } if( pr.bool[ PR_HASIMOUTPUT ]) { convBuf1 = imOutBuf[ ch ]; for( i = 0; i < len; i++ ) { f1 = Math.abs( convBuf1[ i ]); if( f1 > maxAmp ) { maxAmp = f1; } } } } progOff += len; framesWritten += len; // .... progress .... setProgression( (float) progOff / (float) progLen ); } // while not framesWritten // ----==================== normalize output ====================---- if( pr.intg[ PR_GAINTYPE ] == GAIN_UNITY ) { peakGain = new Param( maxAmp, Param.ABS_AMP ); gain = (float) (Param.transform( pr.para[ PR_GAIN ], Param.ABS_AMP, new Param( 1.0 / peakGain.value, peakGain.unit ), null )).value; f1 = pr.bool[ PR_HASIMOUTPUT ] ? ((1.0f + getProgression()) / 2) : 1.0f; normalizeAudioFile( reFloatF, reOutF, reOutBuf, gain, f1 ); if( pr.bool[ PR_HASIMOUTPUT ]) { normalizeAudioFile( imFloatF, imOutF, imOutBuf, gain, 1.0f ); } maxAmp *= gain; for( ch = 0; ch < outChanNum; ch++ ) { reFloatF[ ch ].cleanUp(); reFloatF[ ch ] = null; reTempFile[ ch ].delete(); reTempFile[ ch ] = null; if( pr.bool[ PR_HASIMOUTPUT ]) { imFloatF[ ch ].cleanUp(); imFloatF[ ch ] = null; imTempFile[ ch ].delete(); imTempFile[ ch ] = null; } } } // .... check running .... if( !threadRunning ) break topLevel; // ---- Finish ---- reOutF.close(); reOutF = null; reOutStream = null; if( imOutF != null ) { imOutF.close(); imOutF = null; imOutStream = null; } reInF.close(); reInF = null; reInStream = null; if( pr.bool[ PR_HASIMINPUT ]) { imInF.close(); imInF = null; imInStream = null; } reOutBuf = null; imOutBuf = null; reInBuf = null; imInBuf = null; // inform about clipping/ low level handleClipping( maxAmp ); } catch( IOException e1 ) { setError( e1 ); } catch( OutOfMemoryError e2 ) { reOutBuf = null; imOutBuf = null; reInBuf = null; imInBuf = null; convBuf1 = null; convBuf2 = null; System.gc(); setError( new Exception( ERR_MEMORY )); } // ---- cleanup (topLevel) ---- convBuf1 = null; convBuf2 = null; if( reInF != null ) { reInF.cleanUp(); reInF = null; } if( imInF != null ) { imInF.cleanUp(); imInF = null; } if( reOutF != null ) { reOutF.cleanUp(); reOutF = null; } if( imOutF != null ) { imOutF.cleanUp(); imOutF = null; } if( reFloatF != null ) { for( ch = 0; ch < reFloatF.length; ch++ ) { if( reFloatF[ ch ] != null ) { reFloatF[ ch ].cleanUp(); reFloatF[ ch ] = null; } if( reTempFile[ ch ] != null ) { reTempFile[ ch ].delete(); reTempFile[ ch ] = null; } } } if( imFloatF != null ) { for( ch = 0; ch < imFloatF.length; ch++ ) { if( imFloatF[ ch ] != null ) { imFloatF[ ch ].cleanUp(); imFloatF[ ch ] = null; } if( imTempFile[ ch ] != null ) { imTempFile[ ch ].delete(); imTempFile[ ch ] = null; } } } } // process() // -------- private methods -------- /* * Set new input file */ protected void setInput( String fname ) { AudioFile f = null; AudioFileDescr stream = null; ParamField ggSlave; Param ref; // ---- Header lesen ---- try { f = AudioFile.openAsRead( new File( fname )); stream = f.getDescr(); f.close(); ref = new Param( AudioFileDescr.samplesToMillis( stream, stream.length ), Param.ABS_MS ); ggSlave = (ParamField) gui.getItemObj( GG_OFFSET ); if( ggSlave != null ) { ggSlave.setReference( ref ); } } catch( IOException ignored) {} } protected void reflectPropertyChanges() { super.reflectPropertyChanges(); Component c; c = gui.getItemObj( GG_IMINPUTFILE ); if( c != null ) { c.setEnabled( pr.bool[ PR_HASIMINPUT ]); } c = gui.getItemObj( GG_IMOUTPUTFILE ); if( c != null ) { c.setEnabled( pr.bool[ PR_HASIMOUTPUT ]); } } }