2017-03-08 3 views
1

にメインコントローラと通信し、私はJavaFXのを使用して、単純なシンセサイザープログラムを持っています。 MainControllerクラスとやりとりするために、Metronomeという新しいクラスを作成しようとしています。私はそれ自身のスレッドで実行するためにメトロノームを必要としますが、MainControllerから、特に各ビートにメソッドを実行することができます。メトロノームをオンにしたとき、例えば、それが(それ自身のスレッドで)する必要がある形状の塗りつぶしの色を設定し、メインコントローラにおける方法を通じて音を出します。 MainControllerからのメソッドがループを停止するまで、色を連続的に変更し(オンとオフ)、遅延ループでサウンドを生成します。メトロノームクラスをMainControllerと通信して、それを自分のスレッド上で実行させるにはどうしたらいいですか?Javaの:どのように別々のクラスを作るためにスレッド

編集:だから私は基本的にメインコントローラクラスのメソッドを実行できるようにするメトロノームクラスで私のrun()メソッドが必要です。

public class MainController implements Initializable { 

    public AudioMain audio = new AudioMain(); 
    @ FXML public AnchorPane mainPane; 

    public boolean debugMessages = true; 
    public boolean debugMessages2 = false; 
    public boolean debugMessages3 = false; 

    //public final int numKeys = 13; 
    public int C4 = 60; //The midi pitch of C4 
    public int octave = 4; //The default octave to be assigned 

    public String synthType = "Saw"; 
    public SynthSet synth = new SynthSet(111, synthType); //Creates a new SynthSet of 13 SineWaves 

    public double bpm = 120; 
    public Metronome metronome = new Metronome(bpm); 

    ....some code later.... 

    public void toggleMetronome() { 
     metronome.toggleMet(); 
    } 

    public void lightOn() { 
     metronomeLight.setFill(lightOnColor); 
    } 

    public void lightOff() { 
     metronomeLight.setFill(lightOffColor); 
    } 

そして...いくつかのビジュアルコントロールやメトロノームとTimelineベースメトロノームの

public class Metronome implements Runnable{ 

    public boolean metronomeOn = false; 
    public boolean metronomeSound = true; 
    public boolean metOutputMessages = true; 
    public boolean tick8th = false; 
    public double bpm = 20; 
    public long msPerBeat = (long) (60000/bpm); // Miliseconds per beat 
    public int tickCount = 0; 
    public long nano; 

    public Metronome() { 

    } 

    public Metronome(double beat) { 
     setTempo(beat); 
    } 

    public static void main(String args[]) { 
     Metronome met = new Metronome(); 
     met.metOn(); 
    } 

    @Override 
    public void run() { 
     System.out.println(msPerBeat); 
     while (metronomeOn) { 
      beat(); 
      delay(msPerBeat/2); 
      if (tick8th) beat8th(); 
      delay(msPerBeat/2); 
     } 
    } 

    public void metOn() { 
     if (!metronomeOn) { 
      outMessage("Starting metronome at " + bpm + " bpm"); 
      metronomeOn = true; 
      new Thread(this).start(); 
     } 
    } 

    public void metOff() { 
     if (metronomeOn) { 
      outMessage("Stopping metronome"); 
      metronomeOn = false; 
     } 
    } 
    public void toggleMet() { 
     if (metronomeOn) { 
      metOff(); 
     }else if (!metronomeOn) 
      metOn(); 
    } 

    public void beat() { 
     tickCount++; 
     outMessage("Beep " + tickCount); 
    } 
} 
+0

あなたは通常、条件変数やイベントを使用してこれを行うだろう。それが立てば、あなたの質問はあまりに広すぎてここで答えることはできません。 –

+0

コードスニペットを共有していただけますか?あなたの質問はあまりにも一般的です。答えるのは本当に難しいです。 – nono

+1

別のスレッドではなく、[タイムライン](http://docs.oracle.com/javase/8/javafx/visual-effects-tutorial/basics.htm#BEIIDFJC)を使用してメトロノームを制御することを検討することもできます。タイムラインで[KeyValue](https://docs.oracle.com/javase/8/javafx/api/javafx/animation/KeyValue.html)を使用して、変更リスナーを使用して、値が変更されると操作を実行できます。 – jewelsea

答えて

1

サンプルが表示タイミング破りました。

そのコードの束申し訳ありません。それぞれのコンセプトに別々のクラスを持たず、すべてをインライン化するだけで、より簡潔にすることができますが、(この場合のように)ちょっとしたことがなくなると、別のオブジェクトをよりよく定義することができます。

メトロノームクラスは観測可能なプロパティでビートを生成し、他のクラスはリスナーを使用してビートに反応します。

be still my beating heart

import javafx.animation.*; 
import javafx.application.Application; 
import javafx.beans.binding.Bindings; 
import javafx.beans.property.*; 
import javafx.beans.value.ChangeListener; 
import javafx.geometry.*; 
import javafx.scene.Scene; 
import javafx.scene.control.*; 
import javafx.scene.effect.*; 
import javafx.scene.layout.*; 
import javafx.scene.media.AudioClip; 
import javafx.scene.paint.Color; 
import javafx.scene.shape.Circle; 
import javafx.stage.Stage; 
import javafx.util.Duration; 

public class MetroGnome extends Application { 
    public void start(Stage stage) { 
     Metronome metronome = new Metronome(); 
     TempoControl tempoControl = new TempoControl(metronome); 
     BeatIndicator beatIndicator = new BeatIndicator(metronome); 
     PlayControl playControl = new PlayControl(metronome); 

     HBox layout = new HBox(10, playControl, tempoControl, beatIndicator); 
     layout.setAlignment(Pos.CENTER); 
     layout.setPadding(new Insets(10)); 

     stage.setScene(new Scene(layout)); 
     stage.show(); 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 
} 

class PlayControl extends ToggleButton { 
    public PlayControl(Metronome metronome) { 
     super("Start"); 

     setOnAction(event -> { 
      if (isSelected()) { 
       metronome.start(); 
       setText("Stop"); 
      } else { 
       metronome.stop(); 
       setText("Start"); 
      } 
     }); 
    } 
} 

class TempoControl extends VBox { 
    private static final int MIN_TEMPO = 20; 
    private static final int MAX_TEMPO = 240; 
    private static final int DEFAULT_TEMPO = 120; 

    private Slider tempoSlider = new Slider(MIN_TEMPO, MAX_TEMPO, DEFAULT_TEMPO); 
    private Label tempoLabel = new Label(tempoSlider.getValue() + ""); 

    public TempoControl(Metronome metronome) { 
     super(5); 

     tempoLabel.textProperty().bind(Bindings.format("%.0f", tempoSlider.valueProperty())); 
     setAlignment(Pos.CENTER); 
     getChildren().setAll(tempoLabel, tempoSlider); 

     metronome.setTempo(tempoSlider.getValue()); 
     metronome.tempoProperty().bind(tempoSlider.valueProperty()); 
    } 

    public DoubleProperty valueProperty() { 
     return tempoSlider.valueProperty(); 
    } 
} 

class BeatIndicator extends Circle { 
    // Ting sound from: http://soundbible.com/1628-Ting.html 
    private static final String TING_SOUND = "Ting-Popup_Pixels-349896185.wav"; 

    private static AudioClip ting = new AudioClip(
      BeatIndicator.class.getResource(TING_SOUND).toExternalForm() 
    ); 

    public BeatIndicator(Metronome metronome) { 
     super(10, Color.RED); 
     ChangeListener<Beat> beatChangeListener = (observable, oldValue, newValue) -> { 
      ting.play(); 
      setFill(newValue.getTickTock() == 0 ? Color.GREEN : Color.ORANGE); 
     }; 

     DropShadow dropShadow = new DropShadow(5, (Color) getFill()); 
     fillProperty().addListener((observable, oldValue, newValue) -> 
       dropShadow.setColor((Color) newValue) 
     ); 

     Glow beatEffect = new Glow(); 
     beatEffect.setInput(dropShadow); 

     metronome.isRunningProperty().addListener((observable, oldValue, newValue) -> { 
      if (newValue) { 
       setFill(Color.GREEN); 
       setEffect(beatEffect); 
       metronome.beatProperty().addListener(beatChangeListener); 
      } else { 
       metronome.beatProperty().removeListener(beatChangeListener); 
       setFill(Color.RED); 
       setEffect(null); 
      } 
     }); 
    } 
} 

class Metronome { 
    private final double DEFAULT_TEMPO = 60; 
    private ReadOnlyObjectWrapper<Beat> beat = new ReadOnlyObjectWrapper<>(null); 

    private Timeline timeline = new Timeline(); 

    // tempo is measured in beats per minute. 
    private DoubleProperty tempo = new SimpleDoubleProperty(DEFAULT_TEMPO); 
    private ReadOnlyBooleanWrapper isRunning = new ReadOnlyBooleanWrapper(false); 

    private int tickTock = 0; 

    public Metronome() { 
     timeline.getKeyFrames().addAll(
       new KeyFrame(Duration.seconds(0), event -> { 
        beat.set(new Beat(tickTock, timeline.getCurrentTime())); 
        tickTock = (tickTock + 1) % 2; 
       }), 
       new KeyFrame(
         Duration.seconds(1) 
       ) 
     ); 

     tempo.addListener((observable, oldValue, newValue) -> 
       timeline.setRate(newValue.doubleValue()/60.0) 
     ); 
     timeline.setRate(tempo.getValue()/60.0); 
     timeline.setCycleCount(Timeline.INDEFINITE); 
    } 

    public void start() { 
     tickTock = 0; 
     isRunning.set(true); 
     timeline.playFromStart(); 
    } 

    public void stop() { 
     timeline.stop(); 
     isRunning.set(false); 
    } 

    public double getTempo() { 
     return tempo.get(); 
    } 

    public DoubleProperty tempoProperty() { 
     return tempo; 
    } 

    public void setTempo(double tempo) { 
     this.tempo.set(tempo); 
    } 

    public ReadOnlyObjectProperty<Beat> beatProperty() { 
     return beat.getReadOnlyProperty(); 
    } 

    public ReadOnlyBooleanProperty isRunningProperty() { 
     return isRunning.getReadOnlyProperty(); 
    } 
} 

class Beat { 
    private final Duration currentTime; 
    // tickTock varies switches from one to zero on alternate generated beats. 
    private final int tickTock; 

    public Beat(int tickTock, Duration currentTime) { 
     this.currentTime = currentTime; 
     this.tickTock = tickTock; 
    } 

    public int getTickTock() { 
     return tickTock; 
    } 

    public Duration getCurrentTime() { 
     return currentTime; 
    } 
} 
関連する問題