/*
* Graph2SndDlg.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.GenericFile;
import de.sciss.fscape.io.ImageFile;
import de.sciss.fscape.io.ImageStream;
import de.sciss.fscape.prop.Presets;
import de.sciss.fscape.prop.PropertyArray;
import de.sciss.fscape.session.ModulePanel;
import de.sciss.io.AudioFile;
import de.sciss.io.AudioFileDescr;
import javax.swing.*;
import java.awt.*;
import java.io.IOException;
/**
* This module was supposed to translate a scanned
* Cage score / gesture drawing (Ryoanji) into continuous sound samples.
* The project was never completed and I'm not
* sure if this module works at all.
*/
public class Graph2SndDlg
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_OUTPUTRATE = 2;
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 = "OutputRes";
private static final String PRN_OUTPUTRATE = "OutputRate";
private static final String prText[] = { "", "" };
private static final String prTextName[] = { PRN_INPUTFILE, PRN_OUTPUTFILE };
private static final int prIntg[] = { 0, 0, 0 };
private static final String prIntgName[] = { PRN_OUTPUTTYPE, PRN_OUTPUTRES, PRN_OUTPUTRATE };
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_OUTPUTRATE = GG_OFF_CHOICE + PR_OUTPUTRATE;
private static PropertyArray static_pr = null;
private static Presets static_presets = null;
// -------- public methods --------
/**
* !! setVisible() bleibt dem Aufrufer ueberlassen
*/
public Graph2SndDlg()
{
super( "Graph->Sound Conversion" );
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.superPr = DocumentFrame.static_pr;
fillDefaultAudioDescr( static_pr.intg, PR_OUTPUTTYPE, PR_OUTPUTRES, PR_OUTPUTRATE );
// 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;
PathField[] ggInputs;
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( "File I/O", GroupLabel.ORIENT_HORIZONTAL,
GroupLabel.BRACE_NONE ));
ggInputFile = new PathField( PathField.TYPE_INPUTFILE + PathField.TYPE_FORMATFIELD,
"Select input file" );
ggInputFile.handleTypes( GenericFile.TYPES_IMAGE );
con.gridwidth = 1;
con.weightx = 0.1;
gui.addLabel( new JLabel( "Input image", SwingConstants.RIGHT ));
con.gridheight = 2;
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 + PathField.TYPE_RATEFIELD,
"Select 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( "Output sound", SwingConstants.RIGHT ));
con.gridheight = 2;
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 );
gui.registerGadget( ggOutputFile.getRateGadget(), GG_OUTPUTRATE );
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 h, i, j, k, ch;
float f1, f2, f3;
long progOff, progLen;
ImageFile imgF = null;
AudioFile sndF = null;
ImageStream imgStream = null;
AudioFileDescr sndStream = null;
int width, height, frameSize;
int bitsPerSmp = 8;
int inChanNum, outChanNum;
int framesWritten; // re sound
PathField ggOutput;
byte[] row = null; // raw image (RGB interleaved)
float[][] outBuf;
topLevel: try {
// ---- open input ----
imgF = new ImageFile( pr.text[ PR_INPUTFILE ], GenericFile.MODE_INPUT );
imgStream = imgF.initReader();
width = imgStream.width;
height = imgStream.height;
bitsPerSmp = imgStream.bitsPerSmp;
inChanNum = imgStream.smpPerPixel;
frameSize = width * height;
row = imgF.allocRow();
// ---- open output ----
ggOutput = (PathField) gui.getItemObj( GG_OUTPUTFILE );
if( ggOutput == null ) throw new IOException( ERR_MISSINGPROP );
outChanNum = 1;
sndStream = new AudioFileDescr();
ggOutput.fillStream( sndStream );
sndStream.channels = outChanNum;
sndF = AudioFile.openAsWrite( sndStream );
// .... check running ....
if( !threadRunning ) break topLevel;
// ============================== da processing ==============================
progOff = 0;
progLen = (long) frameSize + (long) height;
// framesRead = 0; // sound-frames!!
framesWritten = 0;
outBuf = new float[ outChanNum ][ height ];
// ============================== read image ==============================
for( i = 0; threadRunning && (i < height); i++ ) {
imgF.readRow( row );
// HSB => RGB XXX
for( ch = 0; ch < 1; ch++ ) { // XXX
// ---------- deinterleave raw image ----------
f1 = 0.0f;
f3 = 0.0f;
if( bitsPerSmp == 8 ) { // deinterleave, scale to -1.0 ... +1.0
for( j = 0, k = ch; j < width; j++, k += inChanNum ) {
f2 = 1.0f - ((float) ((int) row[ k ] & 0xFF) / 0xFF);
f1 += f2 * ((float) j / (float) (width-1));
f3 += f2;
}
} else { // 16 bit
for( j = 0, k = ch; j < width; j++, k += inChanNum ) {
h = k << 1;
f2 = 1.0f - (float) ((((int) row[ h++ ] & 0xFF) << 8) | ((int) row[ h ] & 0xFF)) / (float) 0xFFFF;
f1 += f2 * ((float) j / (float) (width-1));
f3 += f2;
}
}
if( f3 > 0.0f ) {
outBuf[ ch ][ i ] = f1 / f3;
} else {
outBuf[ ch ][ i ] = 0.0f;
}
} // for channels
progOff += width;
// .... progress ....
setProgression( (float) progOff / (float) progLen );
} // for rows
// .... check running ....
if( !threadRunning ) break topLevel;
// ============================== write sound ==============================
sndF.writeFrames( outBuf, 0, height );
progOff += height;
framesWritten += height;
// .... progress ....
setProgression( (float) progOff / (float) progLen );
// .... check running ....
if( !threadRunning ) break topLevel;
// ---- Finish ----
imgF.close();
imgF = null;
sndF.close();
sndF = null;
} // topLevel
catch( IOException e1 ) {
setError( e1 );
}
catch( OutOfMemoryError e2 ) {
outBuf = null;
row = null;
System.gc();
setError( new Exception( ERR_MEMORY ));
}
// ---- cleanup (topLevel) ----
if( imgF != null ) {
imgF.cleanUp();
imgF = null;
}
if( sndF != null ) {
sndF.cleanUp();
sndF = null;
}
}
}