/*
 * Created by Nick on Nov 28, 2004
 *
 */
package jmsltutorial;

import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.FlowLayout;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFrame;

import com.softsynth.jmsl.Composable;
import com.softsynth.jmsl.JMSL;
import com.softsynth.jmsl.JMSLMixerContainer;
import com.softsynth.jmsl.JMSLRandom;
import com.softsynth.jmsl.MusicShape;
import com.softsynth.jmsl.Playable;
import com.softsynth.jmsl.jsyn2.JSynMusicDevice;
import com.softsynth.jmsl.jsyn2.JSynUnitVoiceInstrument;
import com.softsynth.jmsl.jsyn2.unitvoices.FilteredSawtoothBL;
import com.softsynth.jmsl.score.Orchestra;
import com.softsynth.jmsl.score.Score;
import com.softsynth.jmsl.score.ScoreFrame;
import com.softsynth.jmsl.score.SelectionBuffer;
import com.softsynth.jmsl.score.transcribe.BeatDivisionSchemeList;
import com.softsynth.jmsl.score.transcribe.ElementMissedException;
import com.softsynth.jmsl.score.transcribe.SearchPathListExpansionException;
import com.softsynth.jmsl.score.transcribe.Transcriber;
import com.softsynth.jmsl.view.MusicShapeEditor;


/**
 * Edit a MusicShape in the MusicShapeEditor, then transcribe it into a notated
 * Score. This uses a JSynUnitVoiceInstrument demonstrating that timbral
 * dimensions higher than dimension 3 are preserved during transcription.
 * 
 * @author Nick Didkovsky, (c) 2004 All rights reserved, Email:
 *         nick@didkovsky.com
 * 
 */
public class TranscribeToot05 extends JFrame implements ActionListener {

    JSynUnitVoiceInstrument insForMusicShape;
    JSynUnitVoiceInstrument insForScore;
    JMSLMixerContainer mixer;
    MusicShapeEditor musicShapeEditor;
    MusicShape musicShape;
    Score score;
    ScoreFrame scoreFrame;

    Button startButton;
    Button stopButton;
    Button transcribeButton;

    Transcriber transcriber;

    public void init() {
        JMSLRandom.randomize(); 
    }

    public void start() {
        initializeJMSL();
        openMusicDevices();
        buildMixer();
        buildInstruments();        
        buildMusicShape();        
        buildMusicShapeEditor();
        buildGUI();
        scoreFrame = new ScoreFrame();
        transcriber = new Transcriber();
        pack();
        setVisible(true);
    }

    private void initializeJMSL() {
        JMSL.clock.setAdvance(0.1);
    }

    private void openMusicDevices() {
        JSynMusicDevice dev = JSynMusicDevice.instance();
        dev.open();
    }

    private void buildInstruments() {
        insForMusicShape = new JSynUnitVoiceInstrument(8, FilteredSawtoothBL.class.getName());
        insForScore = new JSynUnitVoiceInstrument(8, FilteredSawtoothBL.class.getName());
        mixer.addInstrument(insForMusicShape);
        mixer.addInstrument(insForScore);
    }

    private void buildMixer() {
        mixer = new JMSLMixerContainer();
        mixer.start();       
    }

    private void buildMusicShape() {
        musicShape = new MusicShape(insForMusicShape.getDimensionNameSpace());
        musicShape.prefab();
        musicShape.setInstrument(insForMusicShape);

        // cute trick to change state of buttons when musicShape finishes on its own
        musicShape.addStopPlayable(new Playable() {
            public double play(double playTime, Composable parent) throws InterruptedException {
                startButton.setEnabled(true);
                stopButton.setEnabled(false);
                return playTime;
            }
        });
    }

    private void buildMusicShapeEditor() {
        musicShapeEditor = new MusicShapeEditor();
        musicShapeEditor.addMusicShape(musicShape);
    }

    private void buildGUI() {
        setLayout(new BorderLayout());
        Panel buttonPanel = new Panel();
        buttonPanel.setLayout(new FlowLayout());
        buttonPanel.add(startButton = new Button("Start"));
        buttonPanel.add(stopButton = new Button("Stop"));
        stopButton.setEnabled(false);
        buttonPanel.add(transcribeButton = new Button("Transcribe"));
        startButton.addActionListener(this);
        stopButton.addActionListener(this);
        transcribeButton.addActionListener(this);

        add(BorderLayout.SOUTH, buttonPanel);

        add(BorderLayout.NORTH, mixer.getPanAmpControlPanel());

        add(BorderLayout.CENTER, musicShapeEditor.getComponent());
    }

    public void stop() {
        musicShape.finish();
        try {
            musicShape.waitForDone();
        } catch (InterruptedException e) {
        }
        JMSL.scheduler.stop();
        JMSL.closeMusicDevices();
        scoreFrame.setVisible(false);
        scoreFrame.dispose();
        Score.deleteCanvas();
        SelectionBuffer.disposeEditFrame();
        removeAll();
    }

    private void transcribe() {
        BeatDivisionSchemeList.defaultSetup();
        // protect the original MusicShape by cloning it
        MusicShape shapeToTranscribe = (MusicShape) musicShape.clone();
        // convert durations to absolute times
        shapeToTranscribe.integrate(0);

        Orchestra orch = new Orchestra();
        orch.addInstrument(insForScore);

        score = new Score(1, 800, 500);
        score.setOrchestra(orch);
        score.addMeasure();

        transcriber.setScore(score);
        transcriber.setSourceMusicShape(shapeToTranscribe);

        score.rewind();
        score.setCurrentStaffNumber(0);
        try {
            transcriber.transcribe();
        } catch (SearchPathListExpansionException e) {
            e.printStackTrace();
        } catch (ElementMissedException e) {
            e.printStackTrace();
        }

        scoreFrame.addScore(score);
        scoreFrame.pack();
        scoreFrame.setVisible(true);
    }

    public void actionPerformed(ActionEvent ev) {
        Object source = ev.getSource();
        if (source == startButton) {
            startButton.setEnabled(false);
            stopButton.setEnabled(true);
            musicShape.launch(JMSL.now());
        }
        if (source == stopButton) {
            startButton.setEnabled(true);
            stopButton.setEnabled(false);
            musicShape.finish();
        }
        if (source == transcribeButton) {
            transcribe();
        }

    }

    public static void main(String args[]) {
        TranscribeToot05 test = new TranscribeToot05();
        test.init();
        test.start();
           
    }

}