使用winmm3.dll进行音频播放/回放功能

时间:2014-03-15 17:38:24

标签: c# mp3 playback winmm

我正在使用winmm.dll

使用C#制作MP3播放器

我的回卷功能现在有问题。

当Play功能启动时,我启动一个Timer。

当我启动FFW功能时,我希望它与当前的elapsedTime值相距5000毫秒。

例如,如果我开始播放歌曲并按下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;
            }
         }

    }
}

1 个答案:

答案 0 :(得分:1)

在这行代码中:

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

您连接了elapsedTime和ffw5sec的字符串形式,并且elapsedTime的字符串形式是不可解析的,即您无法将其解析为整数。 同样在你的问题中,你不能告诉别人你正在使用哪个计时器。 在C#.NET框架中,有三种Timer类。

有:

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

但是这些计时器类的字符串形式都不可解析。

System.Timers.Timer的字符串形式为"System.Timers.Timer"System.Threading.Timer的字符串形式为"System.Threading.Timer"System.Windows.Forms.Timer的字符串形式为"System.Windows.Forms.Timer, Interval: {0}" },其中{0}System.Windows.Forms.Timer.Interval属性替换。

我知道你还没有使用System.Threading.Timer,因为在你在问题中发布的代码中,我看到你使用了一个空构造函数来创建计时器Timer()和{{ 1}}不包含带0个参数的构造函数,但我仍然不知道它是System.Threading.Timer还是System.Timers.Timer

seek命令的字符串格式的语法是:

System.Windows.Forms.Timer

其中"seek {0} to {1}" 被要搜索的音频文件的路径和名称或别名替换,在您的情况下,{0}为{0}MyMp3被音频文件中的时间所取代,必须是整数

表达式:{1},不会返回一个可以解析为整数的字符串。

驱动程序无法执行此命令。

还建议使用(elapsedTime.ToString() + ffw5sec.ToString())方法为String.Format函数准备和制作mci字符串命令,而不是使用连接字符串方法,因为String.Format方法更易于使用且更方便比连接字符串的方法。这样你就不会感到困惑并犯错误。 String.Format格式化的mci字符串命令也比串联的mci字符串命令更具可读性。

你做的另一个错误是你首先将elapsedTime和ffw5sec转换为字符串,然后连接它们,然后将结果字符串连接到mci string命令

这样做是错误的。你应该首先添加表示时间的elapsedTime和ffw5sec的整数值,然后将结果转换为字符串并将其连接到mci string命令。

我想说的是你不应该两次调用ToString,但你可以使用它一次。

你制作mci string命令的错误方法是:

mciSendString

制作mci string命令的正确方法是:

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

这仅在elapsedTime为整数的情况下有效,但如果不是,则应使用其中一个将时间作为整数返回的属性。

如果字符串形式的elapsedTime是可解析的,那么你的错误就是mci string命令是:"seek MyMp3 to " + (elapsedTime + ffw5sec).ToString() ,因为你连接" 5000"使用" 6000",结果为" 50006000"。

但是以正确的方式,mci string命令应该是:"seek MyMp3 to 50006000",因为你首先添加5000和6000,结果是11000作为整数。

你甚至根本不必使用"seek MyMp3 to 11000",因为你可以将字符串与整数连接起来,而不仅仅是字符串和字符串,无论如何都会产生字符串。例如,两种情况都有效:

ToString()

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

因此,有更好的方法来制作mci string命令:

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

但是括号仍然很重要,因为没有,5000与mci string命令连接,然后是ffw5sec。结果又是错误的:

"seek MyMp3 to " + (elapsedTime + ffw5sec)

也根本不使用Timer类,因为这个类用于在每个间隔时间调用回调方法,而你在定时器和回调方法之外做其他事情。

Timer类不用于测量经过的时间。您应该使用Stopwatch类,可以在System.Diagnostics命名空间中找到它。系统引用已添加到项目中非常重要,因此您可以在此命名空间中找到此类。

Stopwatch类也有Start方法,就像Timer类一样,但不同之处在于Timer类的Start方法开始执行Elapsed事件或Tick事件或构造函数中给出的回调函数,根据什么正如我之前提到的那样,你正在使用的计时器。

秒表类的实例与任何回调方法都没有联系。相反,它们具有私有时间数据字段,以及公共属性以某种形式返回该时间数据。

"seek MyMp3 to " + elapsedTime + ffw5sec = "seek MyMp3 to 50006000" 属性返回时间长度(64位整数),而秒表运行的所有时间都是以毫秒为单位。

还有ElapsedMilliseconds属性,与ElapsedTicks相同,但返回的时间以刻度单位计算。

超过1000个刻度在一秒内通过而不是毫秒。

Elapsed属性与ElapsedMilliseconds和ElapsedTicks相同,但时间不作为长整数返回,而是作为TimeSpan结构返回,它将秒表实例的私有时间数据也存储为私有,也可以返回为或者int(32位整数),多个单位的long或double,它的属性,如Days,Hours,Milliseconds,Minutes,Seconds,Ticks等等。

无论如何,将elapsedTime的类型从ElapsedMilliseconds更改为Timer,并且不要忘记首先使用System.Diagnostics命名空间才能使用此类。您还需要在项目中引用系统参考。

现在终于可以修复你的命令了:

Stopwatch

这应该很好用,但有时候不要忘记使用重置或重启方法将经过时间重置为零。如果希望秒表在经过时间重置为零后处于运行状态,请使用重启方法。否则只需使用Reset方法。

如果仍有问题,那么你必须使用DllImport来外部mciGetErrorString函数,并在mciSendString不起作用时使用它来找出你的问题,因为你输入的参数不正确。

C#中mciGetErrorString的声明是:

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

建议在其他声明的方法之间将上面的代码添加到C#程序中,无论在哪里,但是在声明入口点Main方法的Program类中。

每当mciSendString无法执行您输入的命令时,它会返回错误代码为整数。

您应该将该错误代码输入到mciGetErrorString中。 mciGetErrorString将修改StringBuilder实例并在其中写入错误字符串。

然后使用Object.ToString()或Console.Write或Console.WriteLine方法输出StringBuilder实例的字符串形式。

输出将描述错误,这就是mciSendString无法执行命令的原因。这将帮助您找出问题所在,并直接考虑您的解决方案。

我希望这一切对你有所帮助。祝你好运!