以前、C#でMIDIを遊ぶプログラムを作りました。これを少し更新してみました。
ボタンで作成していた鍵盤をPictureBoxに変えて、キーイベントを追加しました。そのうち自動演奏機能も付けようとしてますが、いつになるかは気分次第。
ソースコードのご利用はご自由に。
using System;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Windows.Forms;
using System.Collections.Generic;
class Program
{
[STAThread]
static void Main()
{
Application.Run( new FormPiano());
}
}
class FormPiano : Form
{
/*--------------------------------------------------*/
/* 使用するAPIの宣言 */
/*--------------------------------------------------*/
[DllImport( "Winmm.dll")]
extern static uint midiOutOpen( ref long lphmo, uint uDeviceID, uint dwCallback, uint dwCallbackInstance, uint dwFlags);
[DllImport( "Winmm.dll")]
extern static uint midiOutClose( long hmo);
[DllImport( "Winmm.dll")]
extern static uint midiOutShortMsg( long hmo, uint dwMsg);
private const uint MMSYSERR_NOERROR = 0;
private const uint MIDI_MAPPER = 0xffffffff;
private long hMidi;
/*--------------------------------------------------*/
private MenuStrip ms;
private ToolStripMenuItem[][] tsmi;
private Label lbl;
private ComboBox cbx;
private Panel pnl;
private PictureBox pbx;
private Dictionary<Keys, int> keyAssign;
private bool[] keyFlag;
private int mouseX;
private int mouseY;
/*--------------------------------------------------*/
public FormPiano()
{
/*--------------------------------------------------*/
this.ClientSize = new Size( 840, 240);
this.Text = "Hello World!";
this.Load += new EventHandler( this.Form_Load);
this.Closed += new EventHandler( this.Form_Closed);
this.KeyPreview = true;
this.KeyDown += new KeyEventHandler( this.Form_KeyDown);
this.KeyUp += new KeyEventHandler( this.Form_KeyUp);
/*--------------------------------------------------*/
this.CreateMenu();
/*--------------------------------------------------*/
this.CreateCtrl();
}
/*--------------------------------------------------*/
private void Form_Load( object sender, EventArgs e)
{
Console.WriteLine( "Form_Load");
/*--------------------------------------------------*/
this.pnl.AutoScrollPosition = new Point( 280 * 4, 0);
/*--------------------------------------------------*/
this.keyAssign = new Dictionary<Keys, int>();
this.keyAssign.Add( Keys.A, 60);
this.keyAssign.Add( Keys.W, 61);
this.keyAssign.Add( Keys.S, 62);
this.keyAssign.Add( Keys.E, 63);
this.keyAssign.Add( Keys.D, 64);
this.keyAssign.Add( Keys.F, 65);
this.keyAssign.Add( Keys.T, 66);
this.keyAssign.Add( Keys.G, 67);
this.keyAssign.Add( Keys.Y, 68);
this.keyAssign.Add( Keys.H, 69);
this.keyAssign.Add( Keys.U, 70);
this.keyAssign.Add( Keys.J, 71);
this.keyAssign.Add( Keys.K, 72);
this.keyAssign.Add( Keys.O, 73);
this.keyAssign.Add( Keys.L, 74);
/*--------------------------------------------------*/
if( midiOutOpen( ref this.hMidi, MIDI_MAPPER, 0, 0, 0) != MMSYSERR_NOERROR)
{
MessageBox.Show( "midiOutOpen error");
Application.Exit();
}
/*--------------------------------------------------*/
this.keyFlag = new bool[128];
for( int i = 0; i < this.keyFlag.Length; i++)
{
this.keyFlag[i] = false;
}
this.mouseX = 0;
this.mouseY = 0;
}
private void Form_Closed( object sender, EventArgs e)
{
Console.WriteLine( "Form_Closed");
midiOutClose( this.hMidi);
}
/*--------------------------------------------------*/
/* Menu */
/*--------------------------------------------------*/
private void CreateMenu()
{
this.ms = new MenuStrip();
this.tsmi = new ToolStripMenuItem[1][];
this.tsmi[0] = new ToolStripMenuItem[2];
for( int i = 0; i < this.tsmi.Length; i++)
{
for( int j = 0; j < this.tsmi[i].Length; j++)
{
this.tsmi[i][j] = new ToolStripMenuItem();
}
}
this.tsmi[0][0].Text = "File (&F)";
this.tsmi[0][1].Text = "Exit (&X)";
for( int i = 0; i < this.tsmi.Length; i++)
{
this.ms.Items.Add( this.tsmi[i][0]);
for( int j = 1; j < this.tsmi[i].Length; j++)
{
this.tsmi[i][0].DropDownItems.Add( this.tsmi[i][j]);
this.tsmi[i][j].Click += new EventHandler( this.Menu_Click);
}
}
this.Controls.Add( this.ms);
this.MainMenuStrip = ms;
}
private void Menu_Click( object sender, EventArgs e)
{
Console.WriteLine( sender.ToString());
if( sender.ToString() == "Exit (&X)")
{
Application.Exit();
}
}
/*--------------------------------------------------*/
/* Control */
/*--------------------------------------------------*/
private void CreateCtrl()
{
this.lbl = new Label();
this.lbl.SetBounds( 20, this.ms.Height, 60, 20);
this.lbl.Text = "program";
this.Controls.Add( this.lbl);
this.cbx = new ComboBox();
this.cbx.SetBounds( 80, this.ms.Height, 60, 20);
this.cbx.DropDownStyle = ComboBoxStyle.DropDownList;
this.Controls.Add( this.cbx);
for( int i = 0; i < 128; i++)
{
this.cbx.Items.Add( i);
}
this.cbx.SelectedIndex = 0;
this.cbx.SelectedIndexChanged += new EventHandler( this.cbx_SelectedIndexChanged);
this.pnl = new Panel();
this.pnl.SetBounds( 20, this.ms.Height + 20, 800, 200 - this.ms.Height);
this.pnl.Anchor = ( AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom);
this.pnl.BorderStyle = BorderStyle.FixedSingle;
this.pnl.AutoScroll = true;
this.Controls.Add( this.pnl);
this.pbx = new PictureBox();
this.pbx.SetBounds( 0, 0, 3000, 160);
this.pbx.BorderStyle = BorderStyle.FixedSingle;
this.pbx.Paint += new PaintEventHandler( this.pbx_Paint);
this.pbx.MouseDown += new MouseEventHandler( this.pbx_MouseDown);
this.pbx.MouseMove += new MouseEventHandler( this.pbx_MouseMove);
this.pbx.MouseUp += new MouseEventHandler( this.pbx_MouseUp);
this.pnl.Controls.Add( this.pbx);
}
/*--------------------------------------------------*/
/* PictureBox Paint */
/*--------------------------------------------------*/
private void pbx_Paint( object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
Rectangle rect = new Rectangle();
Font fnt = new Font( "Arial", 8);
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
/*----- White Keys -----*/
for( int i = 0; i < 128; i++)
{
int q = i / 12;
int r = i % 12;
if( r == 0 || r == 2 || r == 4 || r == 5 || r == 7 || r == 9 || r == 11)
{
rect.X = 280 * q + 20 * ( r < 5 ? r : r + 1);
rect.Y = 0;
rect.Width = 40;
rect.Height = 160;
Brush b = ( this.keyFlag[i] ? Brushes.Pink : Brushes.White);
Pen p = Pens.Black;
g.FillRectangle( b, rect);
g.DrawRectangle( p, rect);
rect.Y = 120;
rect.Height = 40;
g.DrawString( i.ToString(), fnt, Brushes.Gray, rect, sf);
foreach( KeyValuePair<Keys, int> kvp in this.keyAssign)
{
if( i == kvp.Value)
{
rect.Y = 80;
g.DrawString( ( (char)kvp.Key).ToString(), fnt, Brushes.Gray, rect, sf);
}
}
}
}
/*----- Black Keys -----*/
for( int i = 0; i < 128; i++)
{
int q = i / 12;
int r = i % 12;
if( r == 1 || r == 3 || r == 6 || r == 8 || r == 10)
{
rect.X = 280 * q + 20 * ( r < 5 ? r : r + 1) + 5;
rect.Y = 0;
rect.Width = 30;
rect.Height = 80;
Brush b = ( this.keyFlag[i] ? Brushes.Pink : Brushes.Black);
Pen p = Pens.White;
g.FillRectangle( b, rect);
g.DrawRectangle( p, rect);
rect.Y = 40;
rect.Height = 40;
g.DrawString( i.ToString(), fnt, Brushes.Gray, rect, sf);
foreach( KeyValuePair<Keys, int> kvp in this.keyAssign)
{
if( i == kvp.Value)
{
rect.Y = 0;
g.DrawString( ( (char)kvp.Key).ToString(), fnt, Brushes.Gray, rect, sf);
}
}
}
}
}
/*--------------------------------------------------*/
/* Mouse Event */
/*--------------------------------------------------*/
private void pbx_MouseDown( object sender, MouseEventArgs e)
{
Console.WriteLine( "pbx_MouseDown");
byte key = this.PositionToKey( e.X, e.Y);
if( ( key != 255) && !this.keyFlag[key])
{
this.keyFlag[key] = true;
this.NoteOn( key);
this.mouseX = e.X;
this.mouseY = e.Y;
}
this.pbx.Invalidate();
}
private void pbx_MouseMove( object sender, MouseEventArgs e)
{
if( e.Button != MouseButtons.None)
{
byte key1 = this.PositionToKey( this.mouseX, this.mouseY);
byte key2 = this.PositionToKey( e.X, e.Y);
if( key1 != key2)
{
Console.WriteLine( "pbx_MouseMove");
this.keyFlag[key1] = false;
this.NoteOff( key1);
this.keyFlag[key2] = true;
this.NoteOn( key2);
this.mouseX = e.X;
this.mouseY = e.Y;
this.pbx.Invalidate();
}
}
}
private void pbx_MouseUp( object sender, MouseEventArgs e)
{
Console.WriteLine( "pbx_MouseUp");
byte key = this.PositionToKey( e.X, e.Y);
if( ( key != 255) && this.keyFlag[key])
{
this.keyFlag[key] = false;
this.NoteOff( key);
}
this.pbx.Invalidate();
}
private byte PositionToKey( int x, int y)
{
Rectangle rect = new Rectangle();
/*----- Black Keys -----*/
for( int i = 0; i < 128; i++)
{
int q = i / 12;
int r = i % 12;
if( r == 1 || r == 3 || r == 6 || r == 8 || r == 10)
{
rect.X = 280 * q + 20 * ( r < 5 ? r : r + 1) + 5;
rect.Y = 0;
rect.Width = 30;
rect.Height = 80;
if( rect.X <= x && x < rect.X + rect.Width && rect.Y <= y && y <= rect.Y + rect.Height)
{
return (byte) i;
}
}
}
/*----- White Keys -----*/
for( int i = 0; i < 128; i++)
{
int q = i / 12;
int r = i % 12;
if( r == 0 || r == 2 || r == 4 || r == 5 || r == 7 || r == 9 || r == 11)
{
rect.X = 280 * q + 20 * ( r < 5 ? r : r + 1);
rect.Y = 0;
rect.Width = 40;
rect.Height = 160;
if( rect.X <= x && x < rect.X + rect.Width && rect.Y <= y && y <= rect.Y + rect.Height)
{
return (byte) i;
}
}
}
return 255;
}
/*--------------------------------------------------*/
/* Key Event */
/*--------------------------------------------------*/
private void Form_KeyDown( object sender, KeyEventArgs e)
{
Console.WriteLine( "Form1_KeyDown" + "\t" + e.KeyCode.ToString());
foreach( KeyValuePair<Keys, int> kvp in this.keyAssign)
{
if( e.KeyCode == kvp.Key)
{
byte key = (byte)kvp.Value;
if( !this.keyFlag[key])
{
this.keyFlag[key] = true;
this.NoteOn( key);
}
this.pbx.Invalidate();
return;
}
}
}
private void Form_KeyUp( object sender, KeyEventArgs e)
{
Console.WriteLine( "Form1_KeyUp" + "\t" + ( (int) e.KeyCode).ToString());
foreach( KeyValuePair<Keys, int> kvp in this.keyAssign)
{
if( e.KeyCode == kvp.Key)
{
byte key = (byte)kvp.Value;
if( this.keyFlag[key])
{
this.keyFlag[key] = false;
this.NoteOff( key);
}
this.pbx.Invalidate();
}
}
}
/*--------------------------------------------------*/
/* ComboBox */
/*--------------------------------------------------*/
private void cbx_SelectedIndexChanged(object sender, System.EventArgs e)
{
byte prg = (byte) this.cbx.SelectedIndex;
Console.WriteLine( "cbx_SelectedIndexChanged " + prg.ToString());
this.ProgramChange( prg);
}
/*--------------------------------------------------*/
/* Note On/Off */
/*--------------------------------------------------*/
private void NoteOn( byte key)
{
byte ch = 0; //(byte) ( ( this.cmb[0].SelectedIndex == 0) ? 0 : 9);
byte velocity = 0x7f;
uint msg;
msg = (uint)( ( velocity << 16) + ( key << 8) + 0x90 + ch);
midiOutShortMsg( this.hMidi, msg);
DateTime dt = DateTime.Now;
Console.WriteLine( dt.ToString( "hh:mm:ss.fff") + "\t" + "NoteOn" + "\t" + key.ToString());
}
private void NoteOff( byte key)
{
byte ch = 0; //(byte) ( ( this.cmb[0].SelectedIndex == 0) ? 0 : 9);
byte velocity = 0x7f;
uint msg;
msg = (uint)( ( velocity << 16) + ( key << 8) + 0x80 + ch);
midiOutShortMsg( this.hMidi, msg);
DateTime dt = DateTime.Now;
Console.WriteLine( dt.ToString( "hh:mm:ss.fff") + "\t" + "NoteOff" + "\t" + key.ToString());
}
/*--------------------------------------------------*/
/* Program Change */
/*--------------------------------------------------*/
private void ProgramChange( byte prg)
{
byte ch = (byte) 0;
uint msg;
msg = (uint)( ( prg << 8) + 0xc0 + ch);
midiOutShortMsg( this.hMidi, msg);
}
}