import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Line2D;
import javax.swing.*;
import javax.swing.border.*;
import java.util.*;
import java.io.*;
import javax.sound.sampled.*;
import java.awt.font.*;
import java.text.*;

/**
* Outils d'édition sonore
 */
public class CapturePlayback extends JPanel {
    private static final long serialVersionUID = 42L;
    private static final String name = JavaSoundApplet.dossier+JavaSoundApplet.nomFichier;
	private static final AudioFileFormat.Type fileType = AudioFileFormat.Type.WAVE;
    private static final int bufSize = 16384;
    Capture capture = new Capture();
    Playback playback = new Playback();
	Ajout ajout = new Ajout();
    AudioInputStream audioInputStream,audioInputStreamAjout;
    SamplingGraph samplingGraph;
    JButton playB, captB, pausB, waveB, addB;
	ImageIcon imgRec,imgStop,imgPlay,imgPause,imgValid,imgAdd,imgRaz;
    String errStr, errStrAjout;
    double duration, seconds;
	long indicePause=0; // indice de la pause dans le tableau de bytes
    File file;
    Vector lines = new Vector();
    
	/**
	* Constructeur de l'interface
	*/
    public CapturePlayback() {
        setLayout(new BorderLayout());
        setBorder(new EmptyBorder(2,2,2,2));

		// Récupération des images
		imgRec = new ImageIcon(getClass().getResource("/images/rec.png"));
		imgStop = new ImageIcon(getClass().getResource("/images/stop.png"));
		imgPlay = new ImageIcon(getClass().getResource("/images/play.png"));
		imgPause = new ImageIcon(getClass().getResource("/images/pause.png"));
		imgValid = new ImageIcon(getClass().getResource("/images/valid.png"));
		imgAdd = new ImageIcon(getClass().getResource("/images/add.png"));
		imgRaz = new ImageIcon(getClass().getResource("/images/raz.png"));
		
		
        JPanel p2 = new JPanel();
			p2.setLayout(new BoxLayout(p2, BoxLayout.Y_AXIS));

			JPanel samplingPanel = new JPanel(new BorderLayout());
			samplingPanel.add(samplingGraph = new SamplingGraph());
			p2.add(samplingPanel);
			
			JPanel buttonsPanel = new JPanel();
			captB = addButton("Enregistrer",imgRec, buttonsPanel, true);
			addB = addButton("Ajout",imgAdd, buttonsPanel, false);
			pausB = addButton("Pause", imgPause, buttonsPanel, false);
			playB = addButton("Lire", imgPlay, buttonsPanel, false);
			waveB = addButton("Valider", imgValid,buttonsPanel, false);
			p2.add(buttonsPanel);
		
        add(p2);

        // Actions sur les boutons
        captB.addActionListener(
          new ActionListener(){
            public void actionPerformed(ActionEvent e){
                // ENREGISTRER / RECOMMENCER
                if (captB.getText().startsWith("Enregistrer") || captB.getText().startsWith("Recommencer")) {
                    file = null;
                    audioInputStreamAjout = null; //reset
                    audioInputStream = null;
                    ajout.setExist(false);
                    capture.start();
                    samplingGraph.start();
                    playB.setEnabled(false);
                    pausB.setEnabled(true);
                    waveB.setEnabled(false);
                    addB.setEnabled(false);
                    captB.setText("Stop");
                    captB.setIcon(imgStop);
                }
                // STOP
                else {
                    lines.removeAllElements();
                    capture.stop();
                    samplingGraph.stop();
                    playB.setEnabled(true);
                    pausB.setEnabled(false);
                    waveB.setEnabled(true);
                    addB.setEnabled(true);
                    captB.setText("Recommencer");
                    captB.setIcon(imgRaz);
                    pausB.setText("Pause");
                    pausB.setIcon(imgPause);
                    indicePause=0;
                }
            }
          }
        );

        addB.addActionListener(
          new ActionListener(){
            public void actionPerformed(ActionEvent e){
                // AJOUT SON
                if(addB.getText().startsWith("Ajout")){
                    if(playback.thread != null) {
                        playback.stop(); // On stoppe la lecture
                        samplingGraph.stop();
                    }
                    ajout.start();
                    samplingGraph.start();
                    addB.setText("Fin ajout");
                }
                else{
                    ajout.stop();
                    samplingGraph.stop();
                    playB.setText("Stop");
                    playB.doClick();
                    addB.setText("Ajout");
                }
            }
          }
        );

        pausB.addActionListener(
          new ActionListener(){
            public void actionPerformed(ActionEvent e){
                // PAUSE
                if (pausB.getText().startsWith("Pause")) {
                    if (capture.thread != null) {
                        capture.line.stop();
                        pausB.setText("Reprendre");
                        pausB.setIcon(imgPlay);
                    } else {
                        if (playback.thread != null) {
                            // Interdit la pause 0.8s avant la fin (afin d'éviter un bug) // DEPEND SUREMENT DE LA PUISSANCE DU PC
                            long milliSec = playback.line.getMicrosecondPosition() / 1000;
                            double seconds = (double)milliSec / 1000.0;
                            if(duration - seconds > 0.8){
                                playback.line.stop();
                                indicePause=playback.line.getLongFramePosition()*2;
                                addB.setEnabled(true);
                                pausB.setText("Reprendre");
                                pausB.setIcon(imgPlay);
                                captB.setEnabled(true);
                            }
                        }
                    }
                }
                // REPRENDRE
                else {
                    if (capture.thread != null) {
                        capture.line.start();
                    } else {
                        if (playback.thread != null) {
                            playback.line.start();
                            indicePause=0;
                            addB.setEnabled(false);
                            captB.setEnabled(false);
                        }
                    }
                    pausB.setText("Pause");
                    pausB.setIcon(imgPause);
                }
            }
          }
        );

        playB.addActionListener(
          new ActionListener(){
            public void actionPerformed(ActionEvent e){
                // LIRE
                if (playB.getText().startsWith("Lire")) {
                    playback.start();
                    samplingGraph.start();
                    captB.setEnabled(false);
                    pausB.setEnabled(true);
                    addB.setEnabled(false);
                    playB.setText("Stop");
                    playB.setIcon(imgStop);
                }
                // STOP
                else {
                    playback.stop();
                    captB.setEnabled(true);
                    pausB.setEnabled(false);
                    addB.setEnabled(true);
                    playB.setText("Lire");
                    playB.setIcon(imgPlay);
                    if(pausB.getText().startsWith("Reprendre")){
                        pausB.setText("Pause");
                        pausB.setIcon(imgPause);
                    }
                }
            }
          }
        );

        waveB.addActionListener(
          new ActionListener(){
            public void actionPerformed(ActionEvent e){
                  saveToFile();
            }
          }
        );
    }

	/**
	* Permet d'ajouter un bouton
     * @return un bouton
	*/
    private JButton addButton(String name,ImageIcon icon, JPanel p, boolean state) {
        JButton b = new JButton(name,icon);
        b.setEnabled(state);
		b.setVerticalTextPosition(AbstractButton.BOTTOM);
		b.setHorizontalTextPosition(AbstractButton.CENTER);

        p.add(b);
        return b;
    }

    /**
    * Enregistrement sur le DD
    */
    public void saveToFile() {
        if (audioInputStream == null) {
            reportStatus("No loaded audio to save");
            return;
        }

        // reset to the beginnning of the captured data
        try {
            audioInputStream.reset();
        } catch (Exception e) { 
            reportStatus("Unable to reset stream " + e);
            return;
        }

        File file = new File(name);
        try {
            if (AudioSystem.write(audioInputStream, fileType, file) == -1) {
                throw new IOException("Problems writing to file");
            }
        } catch (Exception ex) { reportStatus(ex.toString()); }
        samplingGraph.repaint();
    }

    /**
     * Ecrit le message d'erreur sur à la place du graphe
     * @param msg
     */
    private void reportStatus(String msg) {
        if ((errStr = msg) != null) {
            System.out.println(errStr);
            samplingGraph.repaint();
        }
    }

    /**
     * Défini les paramètres audios
     * @return
     */
	private AudioFormat getFormat(){
		return new AudioFormat(
							JavaSoundApplet.sampleRate,
						    JavaSoundApplet.sampleSizeInBits,
						    JavaSoundApplet.channels,
						    JavaSoundApplet.signed,
						    JavaSoundApplet.bigEndian);
	}

	/**
	* Write data to the OutputChannel.
	*/
    public class Playback implements Runnable {

        SourceDataLine line;
        Thread thread;

        public void start() {
            errStr = null;
            thread = new Thread(this);
            thread.setName("Playback");
            thread.start();
        }

        public void stop() {
            thread = null;
            samplingGraph.stop();
        }
        
        private void shutDown(String message) {
            if ((errStr = message) != null) {
                System.err.println(errStr);
                samplingGraph.repaint();
            }
			// FERMETURE DU THREAD LECTURE A LA FIN DE LA LECTURE
            if (thread != null) {
                thread = null;
                samplingGraph.stop();
                captB.setEnabled(true);
				addB.setEnabled(true);
                pausB.setEnabled(false);
                playB.setText("Lire");
				playB.setIcon(imgPlay);
            } 
        }

        public void run() {
            // make sure we have something to play
            if (audioInputStream == null) {
                shutDown("No loaded audio to play back");
                return;
            }
            // reset to the beginnning of the stream
            try {
                audioInputStream.reset();
            } catch (Exception e) {
                shutDown("Unable to reset the stream\n" + e);
                return;
            }

            // get an AudioInputStream of the desired format for playback
            AudioFormat format = getFormat();
            AudioInputStream playbackInputStream = AudioSystem.getAudioInputStream(format, audioInputStream);
                        
            if (playbackInputStream == null) {
                shutDown("Unable to convert stream of format " + audioInputStream + " to format " + format);
                return;
            }

            // define the required attributes for our line, 
            // and make sure a compatible line is supported.

            DataLine.Info info = new DataLine.Info(SourceDataLine.class, 
                format);
            if (!AudioSystem.isLineSupported(info)) {
                shutDown("Line matching " + info + " not supported.");
                return;
            }

            // get and open the source data line for playback.

            try {
                line = null;
                line = (SourceDataLine) AudioSystem.getLine(info);
                line.open(format, bufSize);
            } catch (LineUnavailableException ex) { 
                shutDown("Unable to open the line: " + ex);
                return;
            }

            // play back the captured audio data

            int frameSizeInBytes = format.getFrameSize();
            int bufferLengthInFrames = line.getBufferSize() / 8;
            int bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes;
            byte[] data = new byte[bufferLengthInBytes];
            int numBytesRead = 0;

            // start the source data line
            line.start();

            while (thread != null) {
                try {
                    if ((numBytesRead = playbackInputStream.read(data)) == -1) {
                        break;
                    }
                    int numBytesRemaining = numBytesRead;
                    while (numBytesRemaining > 0 ) {
                        numBytesRemaining -= line.write(data, 0, numBytesRemaining);
                    }
                } catch (Exception e) {
                    shutDown("Error during playback: " + e);
                    break;
                }
            }
            // we reached the end of the stream.  let the data play out, then
            // stop and close the line.
            if (thread != null) {
                line.drain();
            }
            line.stop();
            line.close();
            line = null;
            shutDown(null);
        }
    } 

	/** 
	* Reads data from the input channel and writes to the output stream
	*/
    class Capture implements Runnable {

        TargetDataLine line;
        Thread thread;
		byte[] audioBytes;

		public byte[] getAudioBytes(){
			return audioBytes;
		}
		
        public void start() {
            errStr = null;
            thread = new Thread(this);
            thread.setName("Capture");
            thread.start();
        }

        public void stop() {
            thread = null;
        }
        
        private void shutDown(String message) {
            if ((errStr = message) != null && thread != null) {
                thread = null;
                samplingGraph.stop();
                playB.setEnabled(true);
                pausB.setEnabled(false);
                waveB.setEnabled(true);
                captB.setText("Record");
                System.err.println(errStr);
                samplingGraph.repaint();
            }
        }

        public void run() {

            duration = 0;
            audioInputStream = null;
            
            // define the required attributes for our line, 
            // and make sure a compatible line is supported.

            AudioFormat format = getFormat();
            DataLine.Info info = new DataLine.Info(TargetDataLine.class, 
                format);
                        
            if (!AudioSystem.isLineSupported(info)) {
                shutDown("Line matching " + info + " not supported.");
                return;
            }

            // get and open the target data line for capture.

            try {
                line = (TargetDataLine) AudioSystem.getLine(info);
                line.open(format, line.getBufferSize());
            } catch (LineUnavailableException ex) { 
                shutDown("Unable to open the line: " + ex);
                return;
            } catch (SecurityException ex) { 
                shutDown(ex.toString());
                return;
            } catch (Exception ex) { 
                shutDown(ex.toString());
                return;
            }

            // play back the captured audio data
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int frameSizeInBytes = format.getFrameSize();
            int bufferLengthInFrames = line.getBufferSize() / 8;
            int bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes;
            byte[] data = new byte[bufferLengthInBytes];
            int numBytesRead;
            
            line.start();

            while (thread != null) {
                if((numBytesRead = line.read(data, 0, bufferLengthInBytes)) == -1) {
                    break;
                }
                out.write(data, 0, numBytesRead);
            }
            // we reached the end of the stream.  stop and close the line.
            line.stop();
            line.close();
            line = null;

            // stop and close the output stream
            try {
                out.flush();
                out.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }

            // load bytes into the audio input stream for playback

            audioBytes = out.toByteArray();
			System.out.println(audioBytes.length);
            ByteArrayInputStream bais = new ByteArrayInputStream(audioBytes);
            audioInputStream = new AudioInputStream(bais, format, audioBytes.length / frameSizeInBytes);

            long milliseconds = (long)((audioInputStream.getFrameLength() * 1000) / format.getFrameRate());
            duration = milliseconds / 1000.0;

            try {
                audioInputStream.reset();
            } catch (Exception ex) { 
                ex.printStackTrace(); 
                return;
            }

            samplingGraph.createWaveForm(audioBytes);
        }
    } 
	
	/** 
	* Ajoute des morceaux de sons à l'enregistrement
	*/
    class Ajout implements Runnable {
		private TargetDataLine lineAjout;
        Thread threadAjout;
		boolean exist = false;
		ByteArrayOutputStream baos;
		
		public boolean ajoutExistant(){
			return exist;
		}

		public void setExist(boolean ex){
			exist=ex;
		}
		
        public void start() {
            errStrAjout = null;
            threadAjout = new Thread(this);
            threadAjout.setName("Ajout");
            threadAjout.start();
        }

        public void stop() {
            threadAjout = null;
        }
        
        private void shutDown(String message) {
            if ((errStrAjout = message) != null && threadAjout != null) {
                threadAjout = null;
                samplingGraph.stop();
                playB.setEnabled(true);
                pausB.setEnabled(false);
                waveB.setEnabled(true);
                captB.setText("Record");
                System.err.println(errStrAjout);
                samplingGraph.repaint();
            }
        }

        public void run() {

            audioInputStreamAjout = null;
            
            // define the required attributes for our line, 
            // and make sure a compatible line is supported.

            AudioFormat formatAjout = getFormat();
            DataLine.Info infoAjout = new DataLine.Info(TargetDataLine.class, 
                formatAjout);
                        
            if (!AudioSystem.isLineSupported(infoAjout)) {
                shutDown("Line matching " + infoAjout + " not supported.");
                return;
            }
			
            // get and open the target data line for capture.
            try {
				lineAjout = null;
                lineAjout = (TargetDataLine) AudioSystem.getLine(infoAjout);
                lineAjout.open(formatAjout, lineAjout.getBufferSize());
            } catch (LineUnavailableException ex) { 
                shutDown("Unable to open the line: " + ex);
                return;
            } catch (SecurityException ex) { 
                shutDown(ex.toString());
                return;
            } catch (Exception ex) { 
                shutDown(ex.toString());
                return;
            }

            // play back the captured audio data
            ByteArrayOutputStream outAjout = new ByteArrayOutputStream();
            int frameSizeInBytesAjout = formatAjout.getFrameSize();
            int bufferLengthInFramesAjout = lineAjout.getBufferSize() / 8;
            int bufferLengthInBytesAjout = bufferLengthInFramesAjout * frameSizeInBytesAjout;
            byte[] dataAjout = new byte[bufferLengthInBytesAjout];
            int numBytesReadAjout;
            
            lineAjout.start();

            while (threadAjout != null) {
				// LINE => DATAAJOUT
                if((numBytesReadAjout = lineAjout.read(dataAjout, 0, bufferLengthInBytesAjout)) == -1) {
                    break;
                }
				// DATAAJOUT => OUTAJOUT
                outAjout.write(dataAjout, 0, numBytesReadAjout);
            }
			// TT CE QUI SUIT EST ATTEINT QD "STOP AJOUT"
			
			// Délai de 100ms pour pas couper l'enregistrement direct
			try {
				Thread.sleep(100);
			} catch (InterruptedException ie){}
			
            // we reached the end of the stream.  stop and close the line.
			lineAjout.stop();
            //lineAjout.flush();
            lineAjout.close();
            lineAjout = null;

            // stop and close the output stream
            try {
                outAjout.flush();
                outAjout.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }

            // load bytes into the audio input stream for playback

            byte audioBytesAjout[] = outAjout.toByteArray();
			byte audioBytesExistant[];

			if(ajoutExistant()){
				audioBytesExistant = new byte [baos.toByteArray().length];
				audioBytesExistant = baos.toByteArray();
			}
			else{
				audioBytesExistant = new byte [capture.getAudioBytes().length];
				audioBytesExistant = capture.getAudioBytes();
			}
			
			// Concaténation des signaux
			byte[] newAudioBytesAjout = new byte[audioBytesAjout.length+audioBytesExistant.length];
            // Ajout après une pause
			if(indicePause > 0){
				System.arraycopy(audioBytesExistant, 0, newAudioBytesAjout, 0, (int)indicePause); 
				System.arraycopy(audioBytesAjout, 0, newAudioBytesAjout, (int)indicePause, audioBytesAjout.length);
				System.arraycopy(audioBytesExistant, (int)indicePause, newAudioBytesAjout, (int)indicePause+audioBytesAjout.length, audioBytesExistant.length-(int)indicePause); 
				// Remise à zéro
				indicePause = 0;
			}
            // Ajout à la fin
			else{
				System.arraycopy(audioBytesExistant, 0, newAudioBytesAjout, 0, audioBytesExistant.length); 
				System.arraycopy(audioBytesAjout, 0, newAudioBytesAjout, audioBytesExistant.length, audioBytesAjout.length);
			}
			
			// Stocke le tableau pour les prochains ajouts
			baos = new ByteArrayOutputStream();
			baos.write(newAudioBytesAjout, 0, newAudioBytesAjout.length);
			
            ByteArrayInputStream baisAjout = new ByteArrayInputStream(newAudioBytesAjout);
            audioInputStreamAjout = new AudioInputStream(baisAjout, formatAjout, newAudioBytesAjout.length / frameSizeInBytesAjout);

            long millisecondsAjout = (long)((audioInputStreamAjout.getFrameLength() * 1000) / formatAjout.getFrameRate());
            duration = millisecondsAjout / 1000.0;

            try {
                audioInputStream.reset();
            } catch (Exception ex) {
                ex.printStackTrace();
                return;
            }
            
           	// Remplace l'ancien audiostream
			audioInputStream = audioInputStreamAjout;
			
			// Nouvelle courbe
            samplingGraph.createWaveForm(newAudioBytesAjout);
			// Il y a déjà eu un ajout
			exist = true;
            playB.doClick();
        }
    } 
	
	/**
	* Render a WaveForm.
	*/
    class SamplingGraph extends JPanel implements Runnable {
        private static final long serialVersionUID = 42L; 
        private Thread thread;
        private Font font10 = new Font("serif", Font.PLAIN, 10);
        private Font font12 = new Font("serif", Font.PLAIN, 12);
        Color jfcBlue = new Color(204, 204, 255);
        Color pink = new Color(255, 175, 175);
 
        public SamplingGraph() {
            setBackground(new Color(20, 20, 20));
        }

        public void createWaveForm(byte[] audioBytes) {

            lines.removeAllElements();  // clear the old vector

            AudioFormat format = audioInputStream.getFormat();
            if (audioBytes == null) {
                try {
                    audioBytes = new byte[
                        (int) (audioInputStream.getFrameLength() 
                        * format.getFrameSize())];
                    audioInputStream.read(audioBytes);
                } catch (Exception ex) { 
                    reportStatus(ex.toString());
                    return; 
                }
            }

            Dimension d = getSize();
            int w = d.width;
            int h = d.height-15;
            int[] audioData = null;
            if (format.getSampleSizeInBits() == 16) {
                 int nlengthInSamples = audioBytes.length / 2;
                 audioData = new int[nlengthInSamples];
                 if (format.isBigEndian()) {
                    for (int i = 0; i < nlengthInSamples; i++) {
                         /* First byte is MSB (high order) */
                         int MSB = (int) audioBytes[2*i];
                         /* Second byte is LSB (low order) */
                         int LSB = (int) audioBytes[2*i+1];
                         audioData[i] = MSB << 8 | (255 & LSB);
                     }
                 } else {
                     for (int i = 0; i < nlengthInSamples; i++) {
                         /* First byte is LSB (low order) */
                         int LSB = (int) audioBytes[2*i];
                         /* Second byte is MSB (high order) */
                         int MSB = (int) audioBytes[2*i+1];
                         audioData[i] = MSB << 8 | (255 & LSB);
                     }
                 }
             } else if (format.getSampleSizeInBits() == 8) {
                 int nlengthInSamples = audioBytes.length;
                 audioData = new int[nlengthInSamples];
                 if (format.getEncoding().toString().startsWith("PCM_SIGN")) {
                     for (int i = 0; i < audioBytes.length; i++) {
                         audioData[i] = audioBytes[i];
                     }
                 } else {
                     for (int i = 0; i < audioBytes.length; i++) {
                         audioData[i] = audioBytes[i] - 128;
                     }
                 }
            }
               
            int frames_per_pixel = audioBytes.length / format.getFrameSize()/w;
            byte my_byte = 0;
            double y_last = 0;
            int numChannels = format.getChannels();
            for (double x = 0; x < w && audioData != null; x++) {
                int idx = (int) (frames_per_pixel * numChannels * x);
                if (format.getSampleSizeInBits() == 8) {
                     my_byte = (byte) audioData[idx];
                } else {
                     my_byte = (byte) (128 * audioData[idx] / 32768 );
                }
                double y_new = (double) (h * (128 - my_byte) / 256);
                lines.add(new Line2D.Double(x, y_last, x, y_new));
                y_last = y_new;
            }

            repaint();
        }

        public void paint(Graphics g) {

            Dimension d = getSize();
            int w = d.width;
            int h = d.height;
            int INFOPAD = 15;

            Graphics2D g2 = (Graphics2D) g;
            g2.setBackground(getBackground());
            g2.clearRect(0, 0, w, h);
            g2.setColor(Color.white);
            g2.fillRect(0, h-INFOPAD, w, INFOPAD);

            if (errStr != null) {
                g2.setColor(jfcBlue);
                g2.setFont(new Font("serif", Font.BOLD, 18));
                g2.drawString("ERROR", 5, 20);
                AttributedString as = new AttributedString(errStr);
                as.addAttribute(TextAttribute.FONT, font12, 0, errStr.length());
                AttributedCharacterIterator aci = as.getIterator();
                FontRenderContext frc = g2.getFontRenderContext();
                LineBreakMeasurer lbm = new LineBreakMeasurer(aci, frc);
                float x = 5, y = 25;
                lbm.setPosition(0);
                while (lbm.getPosition() < errStr.length()) {
                    TextLayout tl = lbm.nextLayout(w-x-5);
                    if (!tl.isLeftToRight()) {
                        x = w - tl.getAdvance();
                    }
                    tl.draw(g2, x, y += tl.getAscent());
                    y += tl.getDescent() + tl.getLeading();
                }
            } else if (capture.thread != null || ajout.threadAjout != null) {
                g2.setColor(Color.black);
                g2.setFont(font12);
                g2.drawString("Durée : " + arrondi(seconds,"0.00")+"s", 3, h-4);
            } else {
                g2.setColor(Color.black);
                g2.setFont(font12);
                //g2.drawString("File: " + name + "  Length: " + String.valueOf(dura) + "  Position: " + String.valueOf(seconds), 3, h-4);
                g2.drawString("Durée : " + arrondi(duration,"0.00") + "s  Position : " + arrondi(seconds,"0.00")+"s", 3, h-4);

                if (audioInputStream != null) {
                    // .. render sampling graph ..
                    g2.setColor(jfcBlue);
                    for (int i = 1; i < lines.size(); i++) {
                        g2.draw((Line2D) lines.get(i));
                    }

                    // .. draw current position ..
                    if (seconds != 0) {
                        double loc = seconds/duration*w;
                        g2.setColor(pink);
                        g2.setStroke(new BasicStroke(3));
                        g2.draw(new Line2D.Double(loc, 0, loc, h-INFOPAD-2));
                    }
                }
            }
        }
		
		private String arrondi(double value, String format){
			if(format == null  ||  format.length() <= 0) { return String.valueOf(value); }
			return new DecimalFormat(format).format(value);
		}

        public void start() {
            thread = new Thread(this);
            thread.setName("SamplingGraph");
            thread.start();
            seconds = 0;
        }

        public void stop() {
            if (thread != null) {
                thread.interrupt();
            }
            thread = null;
        }

        public void run() {
            seconds = 0;
            while (thread != null) {
                if ((playback.line != null) && (playback.line.isOpen()) ) {

                    long milliseconds = (playback.line.getMicrosecondPosition() / 1000);
                    seconds =  milliseconds / 1000.0;
                } else if ( (capture.line != null) && (capture.line.isActive()) ) {

                    long milliseconds = (capture.line.getMicrosecondPosition() / 1000);
                    seconds =  milliseconds / 1000.0;
                } else if ( (ajout.lineAjout != null) && (ajout.lineAjout.isActive()) ) {

                    long milliseconds = (ajout.lineAjout.getMicrosecondPosition() / 1000);
                    seconds =  milliseconds / 1000.0;
                }

                try { thread.sleep(100); } catch (Exception e) { break; }

                repaint();
                                
                while ((capture.line != null && !capture.line.isActive()) ||
                        (ajout.lineAjout != null && !ajout.lineAjout.isActive()) ||
						(playback.line != null && !playback.line.isOpen())){
                    try { thread.sleep(10); } catch (Exception e) { break; }
                }
            }
            seconds = 0;
            repaint();
        }
    } 
} 
