今回は、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 件のコメント:
コメントを投稿