2

私はwinmm.dllを使用してC#でmp3プレーヤーに取り組んでいます

現在、巻き戻し機能に問題があります。

Play 関数の開始時にタイマーを開始します。

FFW 関数を開始するとき、経過時間の現在の値から ffw 5000ms が必要です。

たとえば、曲の再生を開始して FFW を 6 秒押した場合、再生は 6000ms + 5000ms(ffw5sec) で続行する必要があります。

しかし、何も起こっていません。今回は何を間違えたのですか?

namespace kTP
{
    public class MusicPlayer
    {
        [DllImport("winmm.dll")]
        private static extern long mciSendString(string lpstrCommand, StringBuilder lpstrReturnString, int uReturnLength, int hwndCallback);

        private bool isPlaying = false;
        private int ffw5sec = 5000;

        Timer elapsedTime = new Timer();

        public void Open(string file)
        {
            string command = "open \"" + file + "\" type MPEGVideo alias MyMp3";
            mciSendString(command, null, 0, 0);
        }

        public void Play()
        {
            isPlaying = true;
            elapsedTime.Start();
            elapsedTime.Interval = (1000);

            string command = "play MyMp3";
            mciSendString(command, null, 0, 0);
        }

        public void Pause()
        {
            isPlaying = false;
            string command = "pause MyMp3";
            mciSendString(command, null, 0, 0);
        }

        public void Stop()
        {
            isPlaying = false;
            string command = "stop MyMp3";
            mciSendString(command, null, 0, 0);

            elapsedTime.Stop();

            command = "close MyMp3";
            mciSendString(command, null, 0, 0);
        }

            // return to start of song and resume playback
        public void ReturnToStart()
        {
            isPlaying = true;
            string command = "seek MyMp3 to start";
            mciSendString(command, null, 0, 0);

            command = "play MyMp3";
            mciSendString(command, null, 0, 0);
        }

            // Fast Forward
                // needs a better skip Implementation
        public void FFW()
        {
            if (isPlaying == true)
            {
                string command = "set MyMp3 time format ms";
                mciSendString(command, null, 0, 0);

                command = "seek MyMp3 to " + (elapsedTime.ToString() + ffw5sec.ToString());
                mciSendString(command, null, 0, 0);

                command = "play MyMp3";
                mciSendString(command, null, 0, 0);

                //ffw5sec += 5000;
            }
         }

    }
}
4

1 に答える 1

1

このコード行では:

command = "seek MyMp3 to " + (elapsedTime.ToString() + ffw5sec.ToString());

経過時間と ffw5sec の文字列形式を連結しますが、経過時間の文字列形式は解析できません。つまり、整数に解析できません。また、あなたの質問では、正確に使用しているタイマーを他の人に伝えていません。C# .NET フレームワークには、3 種類の Timer クラスがあります。

がある:

System.Timers.Timer,
System.Threading.Timer, and
System.Windows.Forms.Timer

しかし、これらのタイマー クラスのいずれの文字列形式も解析可能ではありません。

isの文字列形式、System.Timers.Timeris"System.Timers.Timer"の文字列形式、およびSystem.Threading.Timerisの文字列形式で、はプロパティに置き換えられます。"System.Threading.Timer"System.Windows.Forms.Timer"System.Windows.Forms.Timer, Interval: {0}"{0}System.Windows.Forms.Timer.Interval

System.Threading.Timer質問に投稿したコードでは、空のコンストラクターを使用して timer を作成し、Timer()0System.Threading.Timer引数を取るコンストラクターが含まれていないことがわかりますが、それでもわかりません。System.Timers.Timerまたはのいずれかの場合System.Windows.Forms.Timer

seek コマンドの文字列形式の構文は次のとおりです。

"seek {0} to {1}"

ここで{0}、シークするオーディオ ファイルのパスと名前またはエイリアスのいずれかに置き換えられます。この場合、{0} はMyMp3. そして{1}、音声ファイルの時間に置き換えられます。これは整数のみである必要があります

式:(elapsedTime.ToString() + ffw5sec.ToString())は、整数に解析できる文字列をまったく返しません。

ドライバーはこのコマンドを実行できません。

String.Format メソッドは、文字列を連結する方法よりも使いやすく便利であるため、文字列を連結する方法を使用する代わりに、String.Formatメソッドを使用して mci 文字列コマンドを関数用に準備および作成することもお勧めします。mciSendStringそうすれば、混乱して間違いを犯すことはありません。また、String.Format によってフォーマットされた mci 文字列コマンドは、連結された mci 文字列コマンドよりも読みやすくなっています。

もう 1 つの間違いは、最初にlapsedTime と ffw5sec を文字列に変換し、次にそれらを連結してから、結果の文字列を mci string コマンドに連結することです。

このようなことをするのは間違っています。最初に、時間を表す経過時間と ffw5secの整数値を加算してから、結果を文字列に変換し、それを mci string コマンドに連結する必要があります。

私が言おうとしているのは、ToString を 2 回呼び出すべきではなく、1 回だけ使用できるということです。

mci string コマンドを作成した間違った方法は次のとおりです。

"seek MyMp3 to " + (elapsedTime.ToString() + ffw5sec.ToString())"

mci 文字列コマンドを作成する正しい方法は次のとおりです。

"seek MyMp3 to " + (elapsedTime + ffw5sec).ToString()

これは、eplapseTime が整数の場合にのみ機能しますが、そうでない場合は、時間を整数として返すプロパティの 1 つを使用する必要があります。

もしあなたの間違いにより、elapsedTime の文字列形式が解析可能だった場合、mci 文字列コマンドは次"seek MyMp3 to 50006000"のようになりました。これは、"5000" と "6000" を連結した結果が "50006000" であるためです。

しかし、正しい方法では、mci 文字列コマンドは次のようになり"seek MyMp3 to 11000"ます。最初に 5000 と 6000 を加算すると、結果は整数として 11000 になります。

ToString()文字列と文字列だけでなく、文字列と整数を連結できるため、まったく使用する必要はありません。結果はとにかく文字列になります。たとえば、両方のケースが機能します。

"seek MyMp3 to " + **"** 11000 **"** = "seek MyMp3 to 11000",

"seek MyMp3 to " + 11000 = "seek MyMp3 to 11000"

したがって、mci 文字列コマンドを作成するさらに良い方法があります。

"seek MyMp3 to " + (elapsedTime + ffw5sec)

しかし、括弧がないと、5000 が mci 文字列コマンドと連結され、次に ffw5sec になるため、括弧は重要です。結果はまた間違ったものでした:

"seek MyMp3 to " + elapsedTime + ffw5sec = "seek MyMp3 to 50006000"

また、Timer クラスはまったく使用しないでください。このクラスは、タイマーとコールバック メソッドの外部で何か他のことをしているときに、インターバル時間ごとにコールバック メソッドを呼び出すために使用されるためです。

Timer クラスは、経過時間の測定には使用されません。代わりに、System.Diagnostics 名前空間にある Stopwatch クラスを使用する必要があります。System 参照が既にプロジェクトに追加されていることが非常に重要です。これにより、この名前空間でこのクラスを見つけることができます。

Stopwatch クラスには、Timer クラスと同様に Start メソッドもありますが、違いは、Timer クラスの Start メソッドは、タイマーに応じて、Elapsed イベント、Tick イベント、またはコンストラクターで指定されたコールバック関数の実行を開始することです。私が前に述べたように使用します。

Stopwatch クラスのインスタンスは、どのコールバック メソッドにも接続しません。代わりに、プライベートな時間データ フィールドと、その時間データを何らかの形式で返すパブリック プロパティがあります。

ElapsedMillisecondsストップウォッチを実行している間に経過した時間をミリ秒単位で計測した長さ (64 ビット整数) を返すプロパティがあります。

ElapsedTicksと同じプロパティもありますElapsedMillisecondsが、返される時間はティック単位で測定されます。

ミリ秒よりも 1 秒間に 1000 をはるかに超えるティックが通過します。

Elapsed プロパティは ElapsedMilliseconds および ElapsedTicks と同じですが、時間は long 整数として返されるのではなく、ストップウォッチ インスタンスの非公開時間データを非公開として格納する TimeSpan 構造体として返され、いずれかの int ( 32 ビット整数)、日、時間、ミリ秒、分、秒、ティックなどのプロパティによる多くの単位での long または double。

とにかく、eplapseTime のタイプを から に変更し、TimerこのStopwatchクラスを使用するために最初に System.Diagnostics 名前空間を使用することを忘れないでください。また、プロジェクト参照でシステム参照が必要です。

最後に、コマンドを修正できます。

command = String.Format("seek MyMp3 to {0}", elapsedTime.ElapsedMilliseconds + ffw5sec);

これは問題なく動作するはずですが、Reset または Restart メソッドを使用して経過時間をゼロにリセットすることを忘れないでください。経過時間がゼロにリセットされた後にストップウォッチを実行状態にする場合は、Restart メソッドを使用します。それ以外の場合は、Reset メソッドを使用してください。

それでも問題がある場合は、DllImport を使用して mciGetErrorString 関数を外部化し、mciSendString が機能しないときに問題を見つけるために使用する必要があります。これは、誤ったパラメーターを入力したためです。

C# での mciGetErrorString の宣言は次のとおりです。

[DllImport("winmm.dll")]
static extern Int32 mciGetErrorString(Int32 errorCode, StringBuilder errorText, Int32 errorTextSize);

C# プログラムの他の宣言されたメソッドの間に上記のコードを追加することをお勧めしますが、エントリ ポイントの Main メソッドが宣言されている Program クラスに追加することをお勧めします。

入力したコマンドを mciSendString が実行できない場合は常に、整数としてエラー コードを返します。

そのエラー コードを mciGetErrorString に入力する必要があります。mciGetErrorString は StringBuilder インスタンスを変更し、そこにエラー文字列を書き込みます。

次に、Object.ToString() または Console.Write または Console.WriteLine メソッドのいずれかを使用して、StringBuilder インスタンスの文字列形式を出力します。

出力には、mciSendString がコマンドの実行に失敗した理由であるエラーが記述されます。これは、問題を見つけ出し、解決策を直接考えるのに役立ちます。

これがすべてあなたに役立つことを願っています。幸運を!

于 2014-12-20T13:10:16.037 に答える