2020年9月6日日曜日

C#で、もう1回、MIDI その3

 今回は、C#でピアノを作ります。

 以前にも同じようなプログラムを作ったのですが、その時は、ボタンコントロールで鍵盤を作りました。今回はPictureBoxに鍵盤の絵を描いています。


 以下が今回のC#のソースコードです。前回の"MidiAPI.cs"と一緒にコンパイルしてください。


 ソースコードはご自由にご利用ください。ただし、趣味のプログラムなので保証はありません。コメントとかも適当です。プログラミングを勉強する方のご参考にでもなれば。


------------------------------

using System;

using System.Drawing;

using System.Windows.Forms;


class Program

{

[STAThread]


static void Main()

{

Application.Run( new FormPiano());

}

}


class FormPiano : Form

{

private IntPtr hMidi;


private Label[] lbl;

private ComboBox[] cmb;


private Panel pnl;

private PictureBox pbx;


private byte key;

private int keyWidthS = 30;

private int keyWidthL = 40;

private int keyHeight = 160;


public FormPiano()

{

/*--------------------------------------------------*/

/* コントロールの作成 */

/*--------------------------------------------------*/

this.SuspendLayout();


/*--------------------------------------------------*/

this.ClientSize = new Size( 840, 240);

this.Text = "Piano";


this.Load += new EventHandler( this.FormPiano_Load);

this.FormClosed += new FormClosedEventHandler( this.FormPiano_FormClosed);


/*--------------------------------------------------*/

this.CreateOption();


/*--------------------------------------------------*/

this.pnl = new Panel();

this.pnl.SetBounds( 0, 40, 840, 200);

this.pnl.AutoScroll = true;

this.pnl.Anchor = ( AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom);

this.Controls.Add( this.pnl);


this.pbx = new PictureBox();

this.pbx.SetBounds( 0, 0, this.keyWidthL * 75, this.keyHeight);

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);


/*--------------------------------------------------*/

this.ResumeLayout();

}


private void CreateOption()

{

this.lbl = new Label[2];

this.cmb = new ComboBox[2];


/*------------------------------*/

this.lbl[0] = new Label();

this.lbl[0].SetBounds( 0, 0, 60, 40);

    this.lbl[0].TextAlign = ContentAlignment.TopRight;

this.lbl[0].Text = "channel";

this.Controls.Add( this.lbl[0]);


this.cmb[0] = new ComboBox();

this.cmb[0].SetBounds( 60, 0, 60, 40);

this.cmb[0].DropDownStyle = ComboBoxStyle.DropDownList;

this.Controls.Add( this.cmb[0]);


this.cmb[0].Items.Add( "0");

this.cmb[0].Items.Add( "9");

this.cmb[0].SelectedIndex = 0;


/*------------------------------*/

this.lbl[1] = new Label();

this.lbl[1].SetBounds( 120, 0, 60, 40);

    this.lbl[1].TextAlign = ContentAlignment.TopRight;

this.lbl[1].Text = "program";

this.Controls.Add( this.lbl[1]);


this.cmb[1] = new ComboBox();

this.cmb[1].SetBounds( 180, 0, 60, 40);

this.cmb[1].DropDownStyle = ComboBoxStyle.DropDownList;

this.Controls.Add( this.cmb[1]);


for( int i = 0; i < 128; i++)

{

this.cmb[1].Items.Add( i);

}


this.cmb[1].SelectedIndex = 0;

this.cmb[1].SelectedIndexChanged += new EventHandler( this.cmb_SelectedIndexChanged);

}


/*--------------------------------------------------*/

/* 鍵盤の描画 */

/*--------------------------------------------------*/


private void pbx_Paint( object sender, PaintEventArgs e)

{

Graphics g = e.Graphics;


int count;

Rectangle rect;


Font fnt = new Font( "Arial", 8);

StringFormat sf = new StringFormat();

sf.Alignment = StringAlignment.Center;

sf.LineAlignment = StringAlignment.Far;


/* 白 */

count = 0;


for( int i = 0; count < 128; i++)

{

rect = new Rectangle( this.keyWidthL * i, 0, this.keyWidthL - 1, this.keyHeight - 1);

g.FillRectangle( Brushes.White, rect);

g.DrawRectangle( ( ( this.key == count) ? Pens.Red : Pens.Black), rect);

g.DrawString( count.ToString(), fnt, Brushes.Black, rect, sf);


count += ( ( count % 12 == 4 || count % 12 == 11) ? 1 : 2);

}


/* 黒 */

count = 1;


for( int i = 0; count < 128; i++)

{

rect = new Rectangle( this.keyWidthL * ( i + 1) - this.keyWidthS / 2, 0, this.keyWidthS - 1, this.keyHeight / 2 - 1);

g.FillRectangle( Brushes.Black, rect);

g.DrawRectangle( ( ( this.key == count) ? Pens.Red : Pens.Black), rect);

g.DrawString( count.ToString(), fnt, Brushes.White, rect, sf);


i += ( ( count % 12 == 3 || count % 12 == 10) ? 1 : 0);

count += ( ( count % 12 == 3 || count % 12 == 10) ? 3 : 2);

}

}


/*--------------------------------------------------*/

/* MIDIデバイスのOpenとClose

/*--------------------------------------------------*/


private void FormPiano_Load( object sender, EventArgs e)

{

Console.WriteLine( "FormPiano_Load");

if( MidiAPI.midiOutOpen( ref this.hMidi, MidiAPI.MIDI_MAPPER, 0, 0, 0) != MidiAPI.MMSYSERR_NOERROR)

{

MessageBox.Show( "midiOutOpen error");

Application.Exit();

}

this.pnl.AutoScrollPosition = new Point( 1120, 0);

}

private void FormPiano_FormClosed( object sender, EventArgs e)

{

Console.WriteLine( "FormPiano_FormClosed");

MidiAPI.midiOutClose( this.hMidi);

}


/*--------------------------------------------------*/

/* Note On/Off */

/*--------------------------------------------------*/


private void NoteOn( byte key)

{

byte ch = (byte) ( ( this.cmb[0].SelectedIndex == 0) ? 0 : 9);

byte velocity = 0x7f;

uint msg;

msg = (uint)( ( velocity << 16) + ( key << 8) + 0x90 + ch);

MidiAPI.midiOutShortMsg( this.hMidi, msg);

}

private void NoteOff( byte key)

{

byte ch = (byte) ( ( this.cmb[0].SelectedIndex == 0) ? 0 : 9);

byte velocity = 0x7f;

uint msg;

msg = (uint)( ( velocity << 16) + ( key << 8) + 0x80 + ch);

MidiAPI.midiOutShortMsg( this.hMidi, msg);

}


/*--------------------------------------------------*/

/* プログラム変更 */

/*--------------------------------------------------*/


private void ProgramChange( byte prg)

{

byte ch = (byte) 0;


uint msg;

msg = (uint)( ( prg << 8) + 0xc0 + ch);

MidiAPI.midiOutShortMsg( this.hMidi, msg);

}


/*--------------------------------------------------*/

/* コンボボックスの処理 */

/*--------------------------------------------------*/


private void cmb_SelectedIndexChanged(object sender, System.EventArgs e)

{

byte prg = (byte) this.cmb[1].SelectedIndex;


Console.WriteLine( "cmb_SelectedIndexChanged " + prg.ToString());


this.ProgramChange( prg);

}


/*--------------------------------------------------*/

/* マウス処理 */

/*--------------------------------------------------*/


private byte MousePosToKey( object sender, MouseEventArgs e)

{

int q = e.X / ( this.keyWidthL * 7);

int r = e.X % ( this.keyWidthL * 7);


byte k = (byte) ( q * 12);


if( e.Y < this.keyHeight / 2)

{

k += (byte) ( ( ( this.keyWidthL - this.keyWidthS / 2) <= r) ? 1 : 0);

k += (byte) ( ( ( this.keyWidthL + this.keyWidthS / 2) <= r) ? 1 : 0);

k += (byte) ( ( ( this.keyWidthL * 2 - this.keyWidthS / 2) <= r) ? 1 : 0);

k += (byte) ( ( ( this.keyWidthL * 2 + this.keyWidthS / 2) <= r) ? 1 : 0);


k += (byte) ( ( ( this.keyWidthL * 3) <= r) ? 1 : 0);

k += (byte) ( ( ( this.keyWidthL * 4 - this.keyWidthS / 2) <= r) ? 1 : 0);

k += (byte) ( ( ( this.keyWidthL * 4 + this.keyWidthS / 2) <= r) ? 1 : 0);

k += (byte) ( ( ( this.keyWidthL * 5 - this.keyWidthS / 2) <= r) ? 1 : 0);

k += (byte) ( ( ( this.keyWidthL * 5 + this.keyWidthS / 2) <= r) ? 1 : 0);

k += (byte) ( ( ( this.keyWidthL * 6 - this.keyWidthS / 2) <= r) ? 1 : 0);

k += (byte) ( ( ( this.keyWidthL * 6 + this.keyWidthS / 2) <= r) ? 1 : 0);

}

else

{

k += (byte) ( ( r / this.keyWidthL) * 2 + ( ( r < this.keyWidthL * 3) ? 0 : -1));

}


return k;

}


private void pbx_MouseDown( object sender, MouseEventArgs e)

{

this.key = this.MousePosToKey( sender, e);

Console.WriteLine( "pbx_MouseDown " + this.key.ToString());


this.NoteOn( this.key);

this.pbx.Refresh();

}


private void pbx_MouseMove( object sender, MouseEventArgs e)

{

if( e.Button != MouseButtons.Left)

{

return;

}


byte k = this.MousePosToKey( sender, e);


if( this.key == k)

{

return;

}


this.NoteOff( this.key);

this.key = k;

this.NoteOn( this.key);

this.pbx.Refresh();

}


private void pbx_MouseUp( object sender, MouseEventArgs e)

{

this.key = this.MousePosToKey( sender, e);

Console.WriteLine( "pbx_MouseUp " + this.key.ToString());


this.NoteOff( this.key);

this.pbx.Refresh();

}


/*--------------------------------------------------*/

}

0 件のコメント:

コメントを投稿