没有声音

本文关键字:声音 | 更新日期: 2023-09-27 18:16:15

所以我试图使用midoutshortmsg()在c#中播放单个音符。问题是没有声音播放。我想出的播放音符的一种方法是将midououtshortmsg()放入从I =0到10000的for循环中。但是我不相信API应该是这样工作的。

在项目的后期,我想将MIDI执行到Kinect项目中,使用for循环会延迟Kinect的实时反馈。所以for循环方法是不允许的。

下面是我用来播放音符的代码,如果你注释掉for循环,那么就不会播放声音。如有任何帮助,不胜感激。

using System;
using System.Runtime.InteropServices;
using System.Text;
namespace MIDITest
{
    [StructLayout(LayoutKind.Sequential)]
    public struct MidiOutCaps
    {
        public UInt16 wMid;
        public UInt16 wPid;
        public UInt32 vDriverVersion;
        [MarshalAs(UnmanagedType.ByValTStr,
           SizeConst = 32)]
        public String szPname;
        public UInt16 wTechnology;
        public UInt16 wVoices;
        public UInt16 wNotes;
        public UInt16 wChannelMask;
        public UInt32 dwSupport;
    }
class Program
    {
        // MCI INterface
        [DllImport("winmm.dll")]
        private static extern long mciSendString(string command,
           StringBuilder returnValue, int returnLength,
           IntPtr winHandle);
        // Midi API
        [DllImport("winmm.dll")]
        private static extern int midiOutGetNumDevs();
        [DllImport("winmm.dll")]
        private static extern int midiOutGetDevCaps(Int32 uDeviceID,
           ref MidiOutCaps lpMidiOutCaps, UInt32 cbMidiOutCaps);
        [DllImport("winmm.dll")]
        private static extern int midiOutOpen(ref int handle,
           int deviceID, MidiCallBack proc, int instance, int flags);
        [DllImport("winmm.dll")]
        private static extern int midiOutShortMsg(int handle,
           int message);
        [DllImport("winmm.dll")]
        private static extern int midiOutClose(int handle);
        private delegate void MidiCallBack(int handle, int msg,
           int instance, int param1, int param2);
        static void Main()
        {
            int handle = 0;
            var numDevs = midiOutGetNumDevs();
            Console.WriteLine("You have {0} midi output devices", numDevs);
            MidiOutCaps myCaps = new MidiOutCaps();
            var res = midiOutGetDevCaps(0, ref myCaps,
                   (UInt32)Marshal.SizeOf(myCaps));
            res = midiOutOpen(ref handle, 0, null, 0, 0);
            byte[] data = new byte[4];
            data[0] = 0x90;
            data[1] = 50;
            data[2] = 111;
            uint msg = BitConverter.ToUInt32(data, 0);
            for (int i = 0; i < 10000; i++)
            {
                // both hard coding the message and creating it with byte doesn't work
                //res = midiOutShortMsg(handle, 0x007F4A90);
                res = midiOutShortMsg(handle, (int)msg);
            }
            res = midiOutClose(handle);
            Console.ReadLine();
        }
    }
}

没有声音

这是因为midiOutShortMsg没有停止代码的执行,这意味着midiOutClose在音符有时间播放之前被调用。

解决这个问题的一种方法是添加Sleep:
res = midiOutShortMsg(handle, (int)msg);
if (res == 0) // Check success code
{
    System.Threading.Thread.Sleep(length);
}
res = midiOutClose(handle);

其中length为音符完成演奏所需的时间,单位为毫秒。

然而,这几乎肯定是不推荐的。