使用 midiInOpen 委派实现 midi 功能时出错

Posted

技术标签:

【中文标题】使用 midiInOpen 委派实现 midi 功能时出错【英文标题】:Errors on midi functions implementation with Delegation for midiInOpen 【发布时间】:2021-08-08 11:41:03 【问题描述】:

我解决了以下代码的许多错误,但 IntelliSense 没有为其中 6 个提供真正的解决方案(3、4、5 和 6 是相同的)。

错误在下面从 1 到 6 进行编号和注释,Visual Studio 给出了相应的错误。

完整的代码是这个:

(...)

// Extra Libraries
using System.Threading;
using System.Runtime.InteropServices;

namespace MidiMonitorC

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    
        public MainWindow()
        
            InitializeComponent();
        

        [System.Runtime.InteropServices.DllImport("winmm.dll")]
        public static extern int midiInGetNumDevs();
        [System.Runtime.InteropServices.DllImport("winmm.dll")]
        public static extern int midiInGetDevCaps(int uDeviceID, ref MIDIINCAPS lpCaps, uint uSize);
        [System.Runtime.InteropServices.DllImport("winmm.dll")]
        public static extern int midiInOpen(ref int hMidiIn, int uDeviceID, MidiInCallback dwCallback, int dwInstance, int dwFlags);

        (...)

        public delegate int MidiInCallback(int hMidiIn, uint wMsg, int dwInstance, int dwParam1, int dwParam2);
        public MidiInCallback ptrCallback = new MidiInCallback(MidiInProc); // <-- 1. A field initializer cannot reference the non-static field, method or property...
        public const int CALLBACK_FUNCTION = 0x30000;
        public const int MIDI_IO_STATUS = 0x20;

        public delegate void DisplayDataDelegate(object dwParam1);

        public struct MIDIINCAPS
        
            public Int16 wMid; // Manufacturer ID
            public Int16 wPid; // Product ID
            public int vDriverVersion; // Driver version
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
            public string szPname; // Product Name
            public int dwSupport; // Reserved
        

        private int hMidiIn;
        private byte StatusByte;
        private byte DataByte1;
        private byte DataByte2;
        private bool MonitorActive = false;
        private bool HideMidiSysMessages = false;

        public int MidiInProc(int hMidiIn, uint wMsg, int dwInstance, int dwParam1, int dwParam2) // <-- 2. Not all code paths return a value
        
            if (MonitorActive)
                TextBox1.Dispatcher.Invoke(new DisplayDataDelegate(DisplayData), new object[]  dwParam1 );
        

        private void DisplayData(object dwParam1)
        
            if (HideMidiSysMessages & ((dwParam1 & 0xF0) == 0xF0)) // <-- 3. Operator & cannot be applied to operands of type 'object[]' and int
                return;
            else
            
                StatusByte = dwParam1 & 0xFF; // <-- 4. Operator & cannot be applied to operands of type 'object[]' and int
                DataByte1 = (dwParam1 & 0xFF00) >> 8; // <-- 5. Operator & cannot be applied to operands of type 'object[]' and int
                DataByte2 = (dwParam1 & 0xFF0000) >> 16; // <-- 6. Operator & cannot be applied to operands of type 'object[]' and int
                TextBox1.Text += string.Format("0:X2 1:X2 2:X23", StatusByte, DataByte1, DataByte2, "\n");
            
        

        (...)

    

这是针对 WPF 应用程序的。

谢谢

【问题讨论】:

【参考方案1】:

对于问题1,你可以在构造函数或者“window Loaded”事件中初始化你的变量:


       public MainWindow()
        
            InitializeComponent();

            ptrCallback = new MidiInCallback(MidiInProc);
        

        //[...]
        public MidiInCallback ptrCallback;
        //[...]      

对于问题 2,您必须提供 int 类型的返回值。请查找midiInOpen方法的相应文档:


     public int MidiInProc(int hMidiIn, uint wMsg, int dwInstance, int dwParam1, int dwParam2) 
        
            if (MonitorActive)
                TextBox1.Dispatcher.Invoke(new DisplayDataDelegate(DisplayData), new object[]  dwParam1 );
            
            return 0; //or whatever value should be returned by default. 
                
        

对于问题 3 到 6,您必须将对象转换为相应的值,可能根据您的代码转换为 int32:

      private void DisplayData(object dwParam1)
      
      int dwParam1Cast = Convert.ToInt32(dwParam1); 
      if (HideMidiSysMessages & ((dwParam1Cast & 0xF0) == 0xF0)) 
          return;
      else
         
             StatusByte = dwParam1Cast & 0xFF; 
             DataByte1 = (dwParam1Cast & 0xFF00) >> 8; 
             DataByte2 = (dwParam1Cast & 0xFF0000) >> 16; 
             TextBox1.Text += string.Format("0:X2 1:X2 2:X23", StatusByte, DataByte1, DataByte2, "\n");
          
       

【讨论】:

以上是关于使用 midiInOpen 委派实现 midi 功能时出错的主要内容,如果未能解决你的问题,请参考以下文章

使用 Windows MIDI API 出现问题(播放时没有回调)

MidiInProc 回调在哪个上下文中执行?

js实现事件委派

iPhone MIDI 实现

.Net 中的 Midi 实现

VST 主机 - MIDI 到波形转换 (C#)