2016-11-03 20 views
0

私はmidiOutShortMsg()を使ってC#でシングルノートを演奏しようとしています。問題は、サウンドが再生されないことです。ノートを演奏するためにわかった1つの方法は、i = 0から10000までのforループにmidiOutShortMsg()を置くことです。しかし、それがAPIが動作するとは考えられません。C#midioutshortmsg no sound

私はKinectプロジェクトにMIDIを実装し、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(); 
     } 
    } 
} 
+1

このアプローチは間違っていると思います。これを行うには、既存のMIDIライブラリを使用します。私は[naudio](https://github.com/naudio/NAudio)に敬意を表します。これには、すでに十分にテストされるべき、MIDI IOのためのマネージドラッパーが含まれています。なぜ、バイトオーダリングなどを心配して、ミディーラッパーを書くのに膨大な時間を浪費するのではなく、それを使うのですか?それはあなたの時間のトンを節約し、ボックスの普遍的なアプリのサポートをしています。あなたは簡単にプロジェクトに参加することができます(https://www.nuget.org/packages/NAudio/)。 – spender

+0

こんにちは、あなたのご返信ありがとうございます!今日はnaudioで作業していましたが、シングルノートを再生するにはSystem.Threading.Thread.Sleep()を使用する必要があることがわかりました。そして、私は同じノートを再生すると、プログラム全体が停止し、サウンドが再生されないという同じ問題が発生しています。任意の回避策を知りたいですか? – Shinsuke

答えて

0

midiOutShortMsgノートがプレイする時間があった前midiOutCloseが呼び出されることを意味し、コードの実行を停止しないためです。これを克服する

一つの方法は、追加することですSleeplengthはそれが遊んで終了するのノートのために要するミリ秒単位の時間がある

res = midiOutShortMsg(handle, (int)msg); 

if (res == 0) // Check success code 
{ 
    System.Threading.Thread.Sleep(length); 
} 

res = midiOutClose(handle); 

しかし、これはほとんど確実に推奨されていません。

+1

MIDIを使って通常のウィンドウタイマーで何かを行うと、音楽的に最も文盲でない人にも分かりやすいタイミングが得られません。 – spender

+0

あなたのお返事ありがとうBassie!残念ながら、System.Threading.Thread.Sleep()では、Kinectはデフォルトでシングルスレッドなので、プログラム全体が停止します。私はマルチスレッドを検討していますが、キネクトは毎秒30フレームで更新されています。私は偶然スレッドの狂気の量を作りたくないので、他の回避策を知っていれば驚いていました! – Shinsuke

+0

@Shinsuke問題はありません。アプリケーションがサウンドを出力しているかどうかを確認し、サウンドが再生されなくなるまで 'midiOutClose'を呼び出さないでください。 – Bassie