5

演習として、タイマーとしてThread.sleepを使用し、サウンドにJMFを使用して、Javaでメトロノームを作成しようとしています。非常にうまく機能していますが、何らかの理由で、JMFは1分あたり最大207ビートのサウンドしか再生していないようです。

私のメトロノームクラスから:

public void play() {
    soundPlayer.play();
    waitPulse();        
    play();
}

私のSoundPlayerクラスから:

public void play() {
    new Thread(new ThreadPlayer()).start();
}

private class ThreadPlayer implements Runnable {
    public void run() {
        System.out.println("Click");
        player.setMediaTime(new Time(0));
        player.start();
    }   
}

SoundPlayer.play()をスレッドとして機能させて、違いが生じるかどうかをテストしましたが、そうではありません。テンポは約207bpmまで簡単に変更できますが、タイマーを1000bpmに設定しても、サウンドは約207bpmより速く再生されません

System.out.println("Click");ThreadPlayer.run()の中に入れて、ループが正しく機能しているかどうかを確認しました。正しく機能しています。

問題は私のJMFの実装にあるようです。簡単な解決策があると確信していますが、誰かが私を助けてくれますか?

手伝ってくれてどうもありがとう!:)

4

5 に答える 5

9

Thread.sleep()の信頼性が低いことについての答えは正しいです。指定した時間内に正確に戻ることを期待することはできません。実際、特にシステムに負荷がかかっているときに、メトロノームがまったく使用できないことにかなり驚いています。詳細については、Thread.sleep()のドキュメントをお読みください。MIDIに関するMaxBeikirchの答えは、良い提案です。MIDIはタイミングを非常にうまく処理します。

しかし、あなたはオーディオでこれを行う方法を尋ねます。秘訣は、オーディオストリームを開き、メトロノームのクリックの間に無音で埋めて、メトロノームのクリックを必要な場所に挿入することです。これを行うと、サウンドカードはサンプルを一定の速度で再生します(クリック音または無音音が含まれているかどうかに関係なく)。ここで重要なのは、オーディオストリームを開いたままにし、決して閉じないことです。したがって、時計はオーディオハードウェアであり、システム時計ではありません。微妙ですが重要な違いです。

したがって、44100Hzで16ビットのモノラルサンプルを生成しているとしましょう。これは、要求されたレートでクリック音を生成する関数です。このクリック音はスピーカー(および耳)に悪いので、実際に使用する場合は小音量で再生してください。(また、このコードはテストされていません-概念を示すためだけのものです)

int interval = 44100; // 1 beat per second, by default
int count = 0;
void setBPM( float bpm ) {
    interval = ( bpm / 60 ) * 44100 ;
}
void generateMetronomeSamples( short[] s ) {
    for( int i=0; i<s.length; ++i ) {
       s = 0;
       ++count;
       if( count == 0 ) {
          s = Short.MAX_VALUE;
       }
       if( count == interval ) {
          count = 0;
       }
    }
}

setBPMでテンポを設定すると、generateMetronomeSamples()関数を繰り返し呼び出し、JavaSoundを使用してその出力をスピーカーにストリーミングすることで、生成されたサンプルを再生できます。(優れたチュートリアルについては、JSResources.orgを参照してください)

それが機能するようになったら、耳障りなクリック音をWAVやAIFFから得られる音、または短い音などに置き換えることができます。

于 2013-01-04T22:02:16.357 に答える
1

私の仮定は、スレッドの実行時間はスレッドスケジューラの気まぐれ次第であるということであり、おそらく他の誰かがここに飛び込むことができます。JVMがそのスレッドに戻るのにかかる時間を保証することはできません。また、JVMがマシン上でプロセスとして実行されており、OSのプロセススケジューラの影響を受けるため、少なくとも2つのレベルの予測不可能性が見られます。

于 2013-01-04T21:11:19.700 に答える
1

時間をかけてMIDIを見てください!-http ://www.ibm.com/developerworks/library/it/it-0801art38/またはhttp://docs.oracle.com/javase/tutorial/sound/TOC.html。これは、コンピューターで作られたサウンドに関連するすべてのものに最適なソリューションです。

于 2013-01-04T21:08:31.693 に答える
1

Jamie Dubyが言ったように、スレッドに1ミリ秒スリープするように指示したからといって、正確に1ミリ秒でコールバックされるわけではありません。唯一の保証は、Thread.sleep();を呼び出してから少なくとも1ミリ秒が経過したことです。実際には、プロセッサはミリ秒ごとにビープ音を鳴らすのに十分な速度でコードを処理できないため、遅延が発生します。劇的な例が必要な場合は、自家製のタイマークラスを作成し、1ミリ秒を1分間カウントしてみると、タイマーがかなりずれていることがわかります。

ここで本当に答えのクレジットに値する人はマックス・ベイクリッヒです、ミディはあなたがあなたが探しているアウトプットを生み出すことができるようになる唯一の方法です。

于 2013-01-04T21:27:37.383 に答える
0

私はプログラマーよりもミュージシャンとしての経験が豊富ですが、しばらく前に開始したメトロノームアプリケーションを終了したばかりです。同じ問題が発生している理由がわからなかったため、プロジェクトをしばらく保留していました。 。はいThread.sleep()は信頼できない可能性がありますが、私はそのメソッドを使用して優れたメトロノームを作成することができました。

ExecutorService並行クラスを使用しても問題が解決するとは思わないので、試してみるとおっしゃっていました。私の推測では、システムリソースの問題ですが、メトロノームを使用する方法はMIDIであると確信しています。私は生徒にメトロノームを使って練習するように強制し、多くを使用しました。ダニの音質にはあまり関心がありませんでした。タイミングははるかに重要であり、MIDIは他のどのオーディオファイルよりもはるかに高速になります。 。javax.sound.midiSoundAPIのライブラリを使用しました。それであなたの問題は解決すると思います。

正しく動作すると、ティックが不均一になることがあります。これは、Thread.sleep()メソッドの信頼性が低いためです。この問題を解決した方法は、System.nanoTime()メソッドの代わりにメソッドを使用してすべての計算をナノ秒単位System.currentTimeMillis()で実行することでした。スリープ時間をThread.sleep()メソッドに渡す前に、ミリ秒に戻すことを忘れないでください。

メトロノームのコードを自分で理解したい場合に備えて、ここに投稿したくありませんが、見たい場合は、kevin.bigler3@gmail.comにメールを送ってください。 d喜んでお送りします。幸運を。

于 2013-03-13T17:00:04.177 に答える