/*
* ChannelMgrDlg.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:
* 12-May-05 fixed bug in output normalizing
*/
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.util.Param;
import de.sciss.gui.PathEvent;
import de.sciss.gui.PathListener;
import de.sciss.io.AudioFile;
import de.sciss.io.AudioFileDescr;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.EOFException;
import java.io.File;
import java.io.IOException;
import java.util.Properties;
/**
* Processing module for splitting a
* multichannel file into several mono
* files or vice versa.
*/
public class ChannelMgrDlg
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_INPUTLIST = 2;
private static final int PR_OUTPUTLIST = 3;
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_CHANMODE = 3;
private static final int PR_NAMEMODE = 4;
private static final int PR_GAIN = 0; // pr.para
// 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_CHANMODE = "ChanMode";
private static final String PRN_NAMEMODE = "NameMode";
private static final String PRN_INPUTLIST = "InputList";
private static final String PRN_OUTPUTLIST = "OutputList";
private static final String[] CHAN_NAMES = { "Split channels", "Merge channels" };
private static final int CHAN_SPLIT = 0;
private static final int CHAN_MERGE = 1;
private static final String[] NAME_NAMES = { "Spatial (L,C,R)", "Numbers (1,2,3)", "Letters (A,B,C)" };
private static final int NAME_SPATIAL = 0;
private static final int NAME_NUMBERS = 1;
private static final int NAME_LETTERS = 2;
private static final String[][] SPATIAL_NAMES = { {}, { "Mono" }, { "L", "R" }, { "L", "C", "R" }, { "L", "R", "Rs", "Ls" },
{ "L", "C", "R", "Rs", "Ls" }, { "L", "C", "R", "Rs", "Ls", "LFE" },
{ "L", "Lc", "C", "Rc", "R", "Rs", "Ls" }, { "L", "Lc", "C", "Rc", "R", "Rs", "Ls", "LFE" }
};
private static final String[] prText = { "", "", "", "" };
private static final String[] prTextName = { PRN_INPUTFILE, PRN_OUTPUTFILE, PRN_INPUTLIST, PRN_OUTPUTLIST };
private static final int[] prIntg = { 0, 0, GAIN_ABSOLUTE, CHAN_MERGE, NAME_SPATIAL };
private static final String[] prIntgName = { PRN_OUTPUTTYPE, PRN_OUTPUTRES, PRN_GAINTYPE,
PRN_CHANMODE, PRN_NAMEMODE };
private static final Param[] prPara = { null };
private static final String[] prParaName = { PRN_GAIN };
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_CHANMODE = GG_OFF_CHOICE + PR_CHANMODE;
private static final int GG_NAMEMODE = GG_OFF_CHOICE + PR_NAMEMODE;
private static final int GG_GAIN = GG_OFF_PARAMFIELD + PR_GAIN;
private static final int GG_INPUTLIST = GG_OFF_OTHER + 0;
private static final int GG_CMDINDEL = GG_OFF_OTHER + 1;
private static final int GG_CMDINDELALL = GG_OFF_OTHER + 2;
private static final int GG_CMDINUP = GG_OFF_OTHER + 3;
private static final int GG_CMDINDOWN = GG_OFF_OTHER + 4;
private static final int GG_OUTPUTLIST = GG_OFF_OTHER + 10;
private static final int GG_CMDOUTAUTO = GG_OFF_OTHER + 11;
private static final int GG_CMDOUTAUTOALL = GG_OFF_OTHER + 12;
private static final int GG_CMDOUTUP = GG_OFF_OTHER + 13;
private static final int GG_CMDOUTDOWN = GG_OFF_OTHER + 14;
private static PropertyArray static_pr = null;
private static Presets static_presets = null;
private static final String ERR_OUTNUM = "Please update # of output files";
private String outPath = "";
private String outFileName = "";
private String outFileExt = "";
protected JList ggInputList, ggOutputList;
protected DefaultListModel ggInputListModel, ggOutputListModel;
// -------- public methods --------
public ChannelMgrDlg() {
super("Channel Manager");
init2();
}
protected void buildGUI() {
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_GAIN ] = new Param( 0.0, Param.DECIBEL_AMP );
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();
// -------- other init --------
// -------- build GUI --------
GridBagConstraints con;
PathField ggInputFile, ggOutputFile;
Component[] ggGain;
PathField[] ggInputs;
JComboBox ggChanMode, ggNameMode;
JButton ggCmd;
JScrollPane ggInputScroll, ggOutputScroll;
// BasicCellRenderer bcr;
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_CHANMODE:
case GG_NAMEMODE:
pr.intg[ ID - GG_OFF_CHOICE ] = ((JComboBox) e.getSource()).getSelectedIndex();
recalcOutChanNum();
outListToPathField();
break;
}
}
};
ListSelectionListener lsl = new ListSelectionListener() {
public void valueChanged( ListSelectionEvent e )
{
int i;
if( e.getSource() == ggInputList ) {
i = ggInputList.getSelectedIndex();
if( i != -1 ) {
inListToPathField();
}
} else if( e.getSource() == ggOutputList ) {
i = ggOutputList.getSelectedIndex();
if( i != -1 ) {
outListToPathField();
}
}
}
};
PathListener pathL = new PathListener() {
public void pathChanged( PathEvent e )
{
int ID = gui.getItemID( e );
switch( ID ) {
case GG_INPUTFILE:
pr.text[ ID - GG_OFF_PATHFIELD ] = ((PathField) e.getSource()).getPath().getPath();
setInput( pr.text[ ID - GG_OFF_PATHFIELD ]);
recalcOutChanNum();
break;
case GG_OUTPUTFILE:
pr.text[ ID - GG_OFF_PATHFIELD ] = ((PathField) e.getSource()).getPath().getPath();
setOutput( pr.text[ ID - GG_OFF_PATHFIELD ]);
break;
}
}
};
ActionListener al = new ActionListener() {
public void actionPerformed( ActionEvent e )
{
int ID = gui.getItemID( e );
int i;
int[] idx;
Object o;
switch( ID ) {
// input
case GG_CMDINUP:
case GG_CMDINDOWN:
i = ggInputList.getSelectedIndex();
if( (i < (ID == GG_CMDINUP ? 1 : 0)) || ((ID == GG_CMDINDOWN) && (i >= ggInputListModel.size() - 1) )) break;
o = ggInputListModel.remove( i );
i += (ID == GG_CMDINUP) ? -1 : 1;
ggInputListModel.insertElementAt( o, i );
ggInputList.setSelectedIndex( i );
ggInputList.ensureIndexIsVisible( i );
break;
case GG_CMDINDEL:
idx = ggInputList.getSelectedIndices();
if( idx.length == 0 ) break;
for( i = idx.length - 1; i >= 0; i-- ) {
ggInputListModel.removeElementAt( idx[i] );
}
inListToPathField();
recalcOutChanNum();
break;
case GG_CMDINDELALL:
ggInputListModel.removeAllElements();
inListToPathField();
recalcOutChanNum();
outListToPathField();
break;
// output
case GG_CMDOUTUP:
case GG_CMDOUTDOWN:
i = ggOutputList.getSelectedIndex();
if( (i < (ID == GG_CMDOUTUP ? 1 : 0)) || ((ID == GG_CMDOUTDOWN) && (i >= ggOutputListModel.size() - 1) )) break;
o = ggOutputListModel.remove( i );
i += (ID == GG_CMDOUTUP) ? -1 : 1;
ggOutputListModel.insertElementAt( o, i );
ggOutputList.setSelectedIndex( i );
ggOutputList.ensureIndexIsVisible( i );
break;
case GG_CMDOUTAUTO:
i = ggOutputList.getSelectedIndex();
if( i == -1 ) break;
((OutputEntry) ((ListEntry) ggOutputListModel.elementAt( i )).peer).auto = true;
recalcOutChanNum();
outListToPathField();
break;
case GG_CMDOUTAUTOALL:
for( i = 0; i < ggOutputListModel.size(); i++ ) {
((OutputEntry) ((ListEntry) ggOutputListModel.elementAt( i )).peer).auto = true;
}
recalcOutChanNum();
outListToPathField();
break;
}
}
};
// -------- Input-Gadgets --------
con.fill = GridBagConstraints.BOTH;
con.gridwidth = GridBagConstraints.REMAINDER;
gui.addLabel( new GroupLabel( "Input(s)", GroupLabel.ORIENT_HORIZONTAL,
GroupLabel.BRACE_NONE ));
ggInputFile = new PathField( PathField.TYPE_INPUTFILE + PathField.TYPE_FORMATFIELD,
"Select an input file" );
ggInputFile.handleTypes( GenericFile.TYPES_SOUND );
con.gridwidth = 1;
con.weightx = 0.1;
gui.addLabel( new JLabel( "Add file", SwingConstants.RIGHT ));
con.gridwidth = GridBagConstraints.REMAINDER;
con.weightx = 0.9;
gui.addPathField( ggInputFile, GG_INPUTFILE, pathL );
// -------- Command-Gadgets --------
con.fill = GridBagConstraints.BOTH;
con.gridwidth = GridBagConstraints.REMAINDER;
ggInputListModel= new DefaultListModel();
ggInputList = new JList( ggInputListModel );
// bcr = new BasicCellRenderer() {
// public Component getListCellRendererComponent( JList list, Object obj, int index, boolean isSelected,
// boolean cellHasFocus )
// {
// return super.getListCellRendererComponent( list,
// obj instanceof InputEntry ? ((InputEntry) obj).name :
// obj instanceof OutputEntry ? ((OutputEntry) obj).name : obj.toString(),
// index, isSelected, cellHasFocus );
//// if( obj instanceof InputEntry ) {
//// setText( ((InputEntry) obj).name );
//// } else if( obj instanceof OutputEntry ) {
//// setText( ((OutputEntry) obj).name );
//// }
//// return this;
// }
// };
// ggInputList.setCellRenderer( bcr );
ggInputList.addListSelectionListener( lsl );
con.gridwidth = 5;
con.gridheight = 4;
con.weightx = 1.0;
con.weighty = 1.0;
ggInputScroll = new JScrollPane( ggInputList );
gui.addGadget( ggInputScroll, GG_INPUTLIST );
con.gridwidth = GridBagConstraints.REMAINDER;
con.fill = GridBagConstraints.HORIZONTAL;
con.gridheight = 1;
con.weightx = 0.025;
con.weighty = 0.0;
ggCmd = new JButton( "Remove" );
con.gridwidth = GridBagConstraints.RELATIVE;
gui.addButton( ggCmd, GG_CMDINDEL, al );
ggCmd = new JButton( "Remove all" );
con.gridwidth = GridBagConstraints.REMAINDER;
gui.addButton( ggCmd, GG_CMDINDELALL, al );
ggCmd = new JButton( "Move up" );
con.gridwidth = GridBagConstraints.RELATIVE;
gui.addButton( ggCmd, GG_CMDINUP, al );
ggCmd = new JButton( "Move down" );
con.gridwidth = GridBagConstraints.REMAINDER;
gui.addButton( ggCmd, GG_CMDINDOWN, al );
gui.addLabel( new JLabel() );
gui.addLabel( new JLabel() );
// -------- Settings-Gadgets --------
con.fill = GridBagConstraints.HORIZONTAL;
con.gridwidth = GridBagConstraints.REMAINDER;
gui.addLabel( new GroupLabel( "", GroupLabel.ORIENT_HORIZONTAL,
GroupLabel.BRACE_NONE ));
ggChanMode = new JComboBox();
for( int i = 0; i < CHAN_NAMES.length; i++ ) {
ggChanMode.addItem( CHAN_NAMES[ i ]);
}
con.gridwidth = 1;
con.weightx = 0.1;
gui.addLabel( new JLabel( "Operation mode", SwingConstants.RIGHT ));
con.gridwidth = GridBagConstraints.REMAINDER;
con.weightx = 0.9;
gui.addChoice( ggChanMode, GG_CHANMODE, il );
// -------- Output-Gadgets --------
con.fill = GridBagConstraints.BOTH;
con.gridwidth = GridBagConstraints.REMAINDER;
gui.addLabel( new GroupLabel( "Output(s)", GroupLabel.ORIENT_HORIZONTAL,
GroupLabel.BRACE_NONE ));
ggOutputFile = new PathField( PathField.TYPE_OUTPUTFILE + PathField.TYPE_FORMATFIELD +
PathField.TYPE_RESFIELD, "Select an output file" );
ggOutputFile.handleTypes( GenericFile.TYPES_SOUND );
ggInputs = new PathField[ 1 ];
ggInputs[ 0 ] = ggInputFile;
ggOutputFile.deriveFrom( ggInputs, "$D0$F0-$E" );
con.gridwidth = 1;
con.weightx = 0.1;
gui.addLabel( new JLabel( "Filename", SwingConstants.RIGHT ));
con.gridwidth = GridBagConstraints.REMAINDER;
con.weightx = 0.9;
gui.addPathField( ggOutputFile, GG_OUTPUTFILE, pathL );
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 );
// -------- Command-Gadgets --------
con.fill = GridBagConstraints.BOTH;
con.gridwidth = GridBagConstraints.REMAINDER;
ggOutputListModel= new DefaultListModel();
ggOutputList = new JList( ggOutputListModel );
// ggOutputList.setCellRenderer( bcr );
ggOutputList.addListSelectionListener( lsl );
con.gridwidth = 5;
con.gridheight = 4;
con.weightx = 1.0;
con.weighty = 1.0;
ggOutputScroll = new JScrollPane( ggOutputList );
gui.addGadget( ggOutputScroll, GG_OUTPUTLIST );
con.gridwidth = GridBagConstraints.REMAINDER;
con.fill = GridBagConstraints.HORIZONTAL;
con.gridheight = 1;
con.weightx = 0.025;
con.weighty = 0.0;
ggCmd = new JButton( "Auto" );
con.gridwidth = GridBagConstraints.RELATIVE;
gui.addButton( ggCmd, GG_CMDOUTAUTO, al );
ggCmd = new JButton( "Auto all" );
con.gridwidth = GridBagConstraints.REMAINDER;
gui.addButton( ggCmd, GG_CMDOUTAUTOALL, al );
ggCmd = new JButton( "Move up" );
con.gridwidth = GridBagConstraints.RELATIVE;
gui.addButton( ggCmd, GG_CMDOUTUP, al );
ggCmd = new JButton( "Move down" );
con.gridwidth = GridBagConstraints.REMAINDER;
gui.addButton( ggCmd, GG_CMDOUTDOWN, al );
ggNameMode = new JComboBox();
for( int i = 0; i < NAME_NAMES.length; i++ ) {
ggNameMode.addItem( NAME_NAMES[ i ]);
}
con.gridwidth = GridBagConstraints.RELATIVE;
gui.addLabel( new JLabel( "Auto scheme", SwingConstants.RIGHT ));
con.gridwidth = GridBagConstraints.REMAINDER;
gui.addChoice( ggNameMode, GG_NAMEMODE, il );
gui.addLabel( new JLabel() );
initGUI( this, FLAGS_PRESETS | FLAGS_PROGBAR, gui );
}
/**
* Transfer values from prop-array to GUI
*/
public void fillGUI()
{
int num, i;
Properties p;
InputEntry ie;
OutputEntry oe;
String suckMyPlasma = pr.text[ PR_OUTPUTFILE ];
// System.out.println( "A: "+pr.text[ PR_OUTPUTFILE ]);
super.fillGUI();
super.fillGUI( gui );
// System.out.println( "B: "+pr.text[ PR_OUTPUTFILE ]);
// gui.stringToPathField( null, GG_INPUTFILE );
ggInputListModel.removeAllElements();
p = Presets.valueToProperties( getPropertyArray().text[ PR_INPUTLIST ]);
num = p.size();
for( i = 0; i < num; i++ ) {
ie = InputEntry.valueOf( p.getProperty( String.valueOf( i )));
ggInputListModel.addElement ( new ListEntry ( ie ) );
}
ggOutputListModel.removeAllElements();
p = Presets.valueToProperties( getPropertyArray().text[ PR_OUTPUTLIST ]);
num = p.size();
for( i = 0; i < num; i++ ) {
oe = OutputEntry.valueOf( p.getProperty( String.valueOf( i )));
ggOutputListModel.addElement( new ListEntry( oe ));
}
pr.text[ PR_OUTPUTFILE ] = suckMyPlasma;
gui.stringToPathField( pr.text[ PR_OUTPUTFILE ], GG_OUTPUTFILE );
calcOutNameComponents( pr.text[ PR_OUTPUTFILE ]);
}
/**
* Transfer values from GUI to prop-array
*/
public void fillPropertyArray()
{
Properties p;
int i, num;
super.fillPropertyArray();
super.fillPropertyArray( gui );
num = ggInputListModel.size();
p = new Properties();
for( i = 0; i < num; i++ ) {
p.put( String.valueOf( i ), ((ListEntry) ggInputListModel.elementAt( i )).peer.toString() );
}
getPropertyArray().text[ PR_INPUTLIST ] = Presets.propertiesToValue( p );
num = ggOutputListModel.size();
p = new Properties();
for( i = 0; i < num; i++ ) {
p.put( String.valueOf( i ), ((ListEntry) ggOutputListModel.elementAt( i )).peer.toString() );
}
getPropertyArray().text[ PR_OUTPUTLIST ] = Presets.propertiesToValue( p );
}
// -------- Processor Interface --------
protected void process() {
int maxInChanNum, len;
long progOff, progLen;
float f1;
// io
AudioFile[] inF = null;
AudioFileDescr[] inStream = null;
AudioFile[] outF = null;
AudioFileDescr[] outStream = null;
float[][] outBuf;
float[][] inBuf;
float[] convBuf1, convBuf2;
float gain = 1.0f; // gain abs amp
final Param ampRef = new Param( 1.0, Param.ABS_AMP ); // transform-Referenz
int numInputs, numOutputs, outChanNum, totOutChan, outLength;
float maxAmp = 0.0f;
final String inPath = pr.text[ PR_INPUTFILE ].substring( 0, pr.text[ PR_INPUTFILE ].lastIndexOf( File.separatorChar ) + 1 );
PathField ggOutput;
topLevel:
try {
// ---- open input, output; init ----
numInputs = ggInputListModel.size();
inF = new AudioFile[ numInputs ];
inStream = new AudioFileDescr[ numInputs ];
for( int i = 0; i < numInputs; i++ ) {
inF[i] = null;
inStream[i] = null;
}
totOutChan = 0;
maxInChanNum= 0;
outLength = 0x7FFFFFFF;
for( int i = 0; (i < numInputs) && threadRunning; i++ ) {
inF[i] = AudioFile.openAsRead( new File( inPath + ((ListEntry) ggInputListModel.elementAt( i )).peer.getName() ));
inStream[i] = inF[i].getDescr();
maxInChanNum= Math.max( maxInChanNum, inStream[i].channels );
totOutChan += inStream[i].channels;
outLength = (int) Math.min( outLength, inStream[i].length );
}
// .... check running ....
if( !threadRunning ) break topLevel;
if( (outLength < 1) || (totOutChan < 1) ) throw new EOFException( ERR_EMPTY );
numOutputs = pr.intg[ PR_CHANMODE ] == CHAN_SPLIT ? totOutChan : 1;
outChanNum = totOutChan / numOutputs;
if( numOutputs > ggOutputListModel.size() ) throw new IOException( ERR_OUTNUM );
outF = new AudioFile[ numOutputs ];
outStream = new AudioFileDescr[ numOutputs ];
outBuf = new float[ outChanNum ][ 8192 ];
inBuf = new float[ maxInChanNum ][ 8192 ]; // maximum input chan.num -> buffer will work for all input files
for( int i = 0; i < numOutputs; i++ ) {
outF[i] = null;
outStream[i] = null;
}
ggOutput = (PathField) gui.getItemObj( GG_OUTPUTFILE );
if( ggOutput == null ) throw new IOException( ERR_MISSINGPROP );
calcOutNameComponents( pr.text[ PR_OUTPUTFILE ]);
for( int i = 0; (i < numOutputs) && threadRunning; i++ ) {
outStream[i]= new AudioFileDescr( inStream[0] );
ggOutput.fillStream( outStream[i] );
outStream[i].channels = outChanNum;
outStream[i].file = new File(
outPath + outFileName + (pr.intg[ PR_CHANMODE ] == CHAN_SPLIT ?
("-" + ((ListEntry) ggOutputListModel.elementAt( i )).peer.getName ()) : "") + outFileExt );
outF[i] = AudioFile.openAsWrite( outStream[i] );
}
// .... check running ....
if( !threadRunning ) break topLevel;
progLen = (long) totOutChan * (long) outLength * 2;
progOff = 0;
// ---- calc peak amp ----
if( pr.intg[ PR_GAINTYPE ] == GAIN_UNITY ) {
progLen += (long) totOutChan * (long) outLength;
for( int i = 0; (i < numInputs) && threadRunning; i++ ) {
for( int framesRead = 0; (framesRead < outLength) && threadRunning; ) {
len = Math.min( outLength - framesRead, 8192 );
inF[ i ].readFrames( inBuf, 0, len );
framesRead += len;
progOff += len * inStream[i].channels;
// .... progress ....
setProgression( (float) progOff / (float) progLen );
for( int ch = 0; ch < inStream[i].channels; ch++ ) {
convBuf1 = inBuf[ ch ];
for( int j = 0; j < len; j++ ) {
f1 = Math.abs( convBuf1[ j ]);
if( f1 > maxAmp ) {
maxAmp = f1;
}
}
}
}
inF[ i ].seekFrame( 0 ); // return to beginning for copy core
}
// .... check running ....
if( !threadRunning ) break topLevel;
gain = (float) (Param.transform( pr.para[ PR_GAIN ], Param.ABS_AMP,
new Param( 1.0 / maxAmp, Param.ABS_AMP ), null )).value;
} else {
gain = (float) (Param.transform( pr.para[ PR_GAIN ], Param.ABS_AMP, ampRef, null )).value;
}
// ---- copy core ----
for( int framesWritten = 0; (framesWritten < outLength) && threadRunning; ) {
len = Math.min( outLength - framesWritten, 8192 );
for( int i = 0, j = 0, ch = 0; (i < numInputs) && threadRunning; i++ ) {
inF[i].readFrames( inBuf, 0, len );
progOff += len * inStream[i].channels;
// .... progress ....
setProgression( (float) progOff / (float) progLen );
for( int k = 0; k < inStream[i].channels; k++ ) {
if( gain == 1.0f ) {
System.arraycopy( inBuf[k], 0, outBuf[ch], 0, len );
} else {
convBuf1 = inBuf[k];
convBuf2 = outBuf[ch];
for( int m = 0; m < len; m++ ) {
convBuf2[m] = convBuf1[m] * gain;
}
}
if( ++ch == outChanNum ) {
outF[j].writeFrames( outBuf, 0, len );
progOff += len * outChanNum;
// .... progress ....
setProgression( (float) progOff / (float) progLen );
ch = 0;
j++;
}
}
if( pr.intg[ PR_GAINTYPE ] == GAIN_ABSOLUTE ) {
for( int k = 0; k < inStream[i].channels; k++ ) {
convBuf1 = inBuf[ k ];
for( int m = 0; m < len; m++ ) {
f1 = Math.abs( convBuf1[ m ]);
if( f1 > maxAmp ) {
maxAmp = f1;
}
}
}
}
}
framesWritten += len;
}
// .... check running ....
if( !threadRunning ) break topLevel;
// ---- finish ----
for( int i = 0; i < numInputs; i++ ) {
inF[i].close();
inF[i] = null;
inStream[i] = null;
}
for( int i = 0; i < numOutputs; i++ ) {
outF[i].close();
outF[i] = null;
outStream[i] = 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 ) {
for( int i = 0; i < outF.length; i++ ) {
if( outF[i] != null ) {
outF[i].cleanUp();
}
}
}
if( inF != null ) {
for( int i = 0; i < inF.length; i++ ) {
if( inF[i] != null ) {
inF[i].cleanUp();
}
}
}
} // process()
// -------- private methods --------
/**
* Set new input file
*/
protected void setInput(String fname) {
AudioFile f = null;
AudioFileDescr stream = null;
int i;
InputEntry ie;
// ---- Header lesen ----
try {
f = AudioFile.openAsRead( new File( fname ));
stream = f.getDescr();
f.close();
ie = new InputEntry();
ie.name = fname.substring( fname.lastIndexOf( File.separatorChar ) + 1 );
ie.chan = stream.channels;
if( ggInputList == null ) {
obscure();
return;
}
i = ggInputList.getSelectedIndex();
if( i >= 0 ) {
ggInputList.clearSelection(); // deselect( i );
}
i = ggInputListModel.size();
ggInputListModel.add( i, new ListEntry( ie ));
ggInputList.setSelectedIndex( i );
ggInputList.ensureIndexIsVisible( i );
// guiToBatchEntry( be );
// recalcChannelSituation();
} catch( IOException ignored) {}
}
protected String calcOutNameComponents(String fname) {
int fIdx = fname.lastIndexOf( File.separatorChar ) + 1;
int eIdx = fname.lastIndexOf( '.' );
int cIdx = fname.lastIndexOf( '-' );
String cExt;
outPath = fname.substring( 0, fIdx );
if( (eIdx <= cIdx) || (eIdx <= fIdx) ) {
eIdx = fname.length();
}
if( cIdx < fIdx ) {
cIdx = eIdx;
}
outFileName = fname.substring( fIdx, cIdx );
outFileExt = fname.substring( eIdx );
cExt = fname.substring( Math.min( eIdx, cIdx + 1 ), eIdx );
return cExt;
}
/**
* Set new output file
*/
protected void setOutput(String fname) {
String cExt = calcOutNameComponents( fname );
int i;
OutputEntry currentOutEntry;
i = ggOutputList.getSelectedIndex();
if( i == -1 ) return;
currentOutEntry = ((OutputEntry) ((ListEntry) ggOutputListModel.elementAt( i )).peer);
if( (cExt.equals( currentOutEntry.name )) || (pr.intg[ PR_CHANMODE ] == CHAN_MERGE) ) return;
currentOutEntry.name = cExt;
currentOutEntry.auto = false;
ggOutputListModel.setElementAt( new ListEntry(currentOutEntry), i );
ggOutputList.ensureIndexIsVisible( i );
ggOutputList.setSelectedIndex( i );
}
protected void obscure() {
if (this.isVisible()) {
JOptionPane.showMessageDialog(getComponent(), "Oscure! Gadget missing...");
}
}
/**
* Copy filename from input list to input path field
*/
protected void inListToPathField() {
int i = ggInputList.getSelectedIndex();
InputEntry currentInEntry;
if( i == -1 ) return;
currentInEntry = (InputEntry) ((ListEntry) ggInputListModel.elementAt( i )).peer;
PathField ggInputFile = (PathField) gui.getItemObj( GG_INPUTFILE );
String fPath;
if( ggInputFile == null ) {
obscure();
return;
}
fPath = ggInputFile.getPath().getPath();
ggInputFile.setPath( new File( fPath.substring( 0, fPath.lastIndexOf( File.separatorChar ) + 1 ) + currentInEntry.name ));
}
/**
* Copy filename from output list to output path field
*/
protected void outListToPathField() {
PathField ggOutputFile = (PathField) gui.getItemObj( GG_OUTPUTFILE );
int i = ggOutputList.getSelectedIndex();
OutputEntry currentOutEntry = (i != -1) ? (OutputEntry) ((ListEntry) ggOutputListModel.elementAt( i )).peer : null;
if( ggOutputFile == null ) {
obscure();
return;
}
ggOutputFile.setPath( new File( outPath + outFileName +
(pr.intg[ PR_CHANMODE ] == CHAN_SPLIT ? ("-" + (currentOutEntry == null ? "" : currentOutEntry.name)) : "") + outFileExt ));
}
protected void recalcOutChanNum() {
int i, ch, oldIdx;
OutputEntry oe;
for( i = 0, ch = 0; i < ggInputListModel.size(); i++ ) {
ch += ((InputEntry) ((ListEntry) ggInputListModel.elementAt( i )).peer).chan;
}
if( pr.intg[ PR_CHANMODE ] == CHAN_MERGE ) {
ch = Math.min( 1, ch );
}
int guiOutChanNum = ch;
oldIdx = ggOutputList.getSelectedIndex();
if( oldIdx >= 0 ) {
ggOutputList.clearSelection(); // ( oldIdx );
}
if( guiOutChanNum < ggOutputListModel.size() ) {
for(i = ggOutputListModel.size() - 1; i >= guiOutChanNum; i-- ) {
ggOutputListModel.removeElementAt( i );
}
}
for( i = 0; i < ggOutputListModel.size(); i++ ) {
oe = (OutputEntry) ((ListEntry) ggOutputListModel.elementAt( i )).peer;
if( oe.auto ) {
oe.name = createAutoExt( i, guiOutChanNum);
ggOutputListModel.setElementAt( new ListEntry( oe ), i );
}
}
while( guiOutChanNum > ggOutputListModel.size() ) {
oe = new OutputEntry();
oe.auto = true;
oe.name = createAutoExt( ggOutputListModel.size(), guiOutChanNum);
ggOutputListModel.addElement( new ListEntry( oe ));
}
if( (oldIdx >= 0) && (oldIdx < guiOutChanNum) ) {
ggOutputList.setSelectedIndex( oldIdx );
ggOutputList.ensureIndexIsVisible( oldIdx );
}
}
protected String createAutoExt(int index, int totalCount) {
int mode = pr.intg[ PR_NAMEMODE ];
String cExt = "";
if( ((mode == NAME_SPATIAL) && (totalCount > 8)) ||
((mode == NAME_LETTERS) && (totalCount > 26)) ) mode = NAME_NUMBERS;
switch( mode ) {
case NAME_SPATIAL:
cExt = SPATIAL_NAMES[ totalCount ][ index ];
break;
case NAME_NUMBERS:
cExt = String.valueOf( index + 1 );
break;
case NAME_LETTERS:
cExt = String.valueOf( ((char) (index + 65)) );
break;
default:
break;
}
return cExt;
}
static interface Entry {
public String getName();
}
static class ListEntry {
private final Entry peer;
public ListEntry(Entry peer) {
this.peer = peer;
}
@Override
public String toString ()
{
return peer.getName ();
}
}
/**
* Internal class for list entries
*/
static class InputEntry implements Entry {
String name;
int chan;
private final static String PR_NAME = "nam";
private final static String PR_CHAN = "cha";
public String getName ()
{
return name;
}
// -------- StringComm methods --------
public String toString() {
Properties p = new Properties();
p.put(PR_NAME, this.name);
p.put(PR_CHAN, String.valueOf(this.chan));
return (Presets.propertiesToValue(p));
}
public static InputEntry valueOf( String s )
{
Properties p = Presets.valueToProperties( s );
InputEntry ie = new InputEntry();
ie.name = p.getProperty( PR_NAME );
try {
ie.chan = Integer.parseInt( p.getProperty( PR_CHAN ));
}
catch( NumberFormatException ignored) {}
catch( NullPointerException ignored) {}
return ie;
}
}
/**
* Internal class for list entries
*/
static class OutputEntry implements Entry {
String name;
boolean auto;
private final static String PR_NAME = "nam";
private final static String PR_AUTO = "aut";
public String getName ()
{
return name;
}
// -------- StringComm methods --------
public String toString() {
Properties p = new Properties();
p.put(PR_NAME, this.name);
p.put(PR_AUTO, String.valueOf(this.auto));
return (Presets.propertiesToValue(p));
}
public static OutputEntry valueOf(String s) {
Properties p = Presets.valueToProperties(s);
OutputEntry oe = new OutputEntry();
oe.name = p.getProperty(PR_NAME);
try {
oe.auto = Boolean.valueOf(p.getProperty(PR_AUTO)).booleanValue();
} catch (NumberFormatException ignored) {
} catch (NullPointerException ignored) {
}
return oe;
}
}
}