今回は、MIDIの演奏のWindowsプログラムです。これまでの内容を組み合わせただけです。
本当はMIDI編集用のプログラムも作ろうかと思ったのですが、いい感じのユーザーインターフェースが思いつかなかったので。。。
気が向いたら、またいろいろ追加、更新しようと思います。
以下が今回のC#のソースコードです。これまでに作った"MidiAPI.cs", "MidiEvent.cs", "MidiFile.cs", "MidiPlayer.cs"も使うので、その5ファイルを合わせてコンパイルしてください。
ソースコードはご自由にご利用ください。ただし、趣味のプログラムなので保証はありません。コメントとかも適当です。プログラミングを勉強する方のご参考にでもなれば。
------------------------------
using System;
using System.Drawing;
using System.Windows.Forms;
class Program
{
[STAThread]
static void Main()
{
Application.Run( new FormMidiView());
}
}
/*--------------------------------------------------*/
class FormMidiView : Form
{
private MenuStrip ms;
private ToolStripMenuItem[][] tsmi;
private ComboBox cbx;
private TextBox tbx;
private ListBox lbx;
MidiPlayer player;
private int TimeDivision;
private MidiEvent[][] Track;
private MidiEvent[][] trk; //Track再生用
private Timer tmr;
/*--------------------------------------------------*/
public FormMidiView()
{
/*--------------------------------------------------*/
/* コントロールの作成 */
/*--------------------------------------------------*/
this.SuspendLayout();
/*--------------------------------------------------*/
this.ClientSize = new Size( 400, 300);
this.Text = "MidiView";
this.Load += new EventHandler( this.Form_Load);
this.FormClosed += new FormClosedEventHandler( this.Form_FormClosed);
this.AllowDrop = true;
this.DragEnter += new DragEventHandler( this.Form_DragEnter);
this.DragDrop += new DragEventHandler( this.Form_DragDrop);
/*--------------------------------------------------*/
this.CreateMenu();
/*--------------------------------------------------*/
this.cbx = new ComboBox();
this.cbx.SetBounds( 0, this.ms.Height, 100, 40);
this.cbx.Anchor = AnchorStyles.Left | AnchorStyles.Top;
this.cbx.SelectedIndexChanged += new EventHandler( this.cbx_SelectedIndexChanged);
this.Controls.Add( this.cbx);
this.tbx = new TextBox();
this.tbx.SetBounds( 0, this.ms.Height + this.cbx.Height, this.ClientSize.Width, 40);
this.tbx.BorderStyle = BorderStyle.None;
this.tbx.ReadOnly = true;
this.tbx.Anchor = AnchorStyles.Left | AnchorStyles.Top;
this.tbx.Text = "Index\tTime\tEvent\tParam1\tParam2\tType\tLength";
this.Controls.Add( this.tbx);
this.lbx = new ListBox();
this.lbx.SetBounds( 0, this.ms.Height + this.cbx.Height + this.tbx.Height, this.ClientSize.Width, this.ClientSize.Height - this.ms.Height - this.cbx.Height - this.tbx.Height);
this.lbx.Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom;
this.Controls.Add( this.lbx);
/*--------------------------------------------------*/
/* Timer */
/* 表示更新用のタイマー。ちなみに、MIDIを再生しているThreadからListBoxの表示を変更するにはDelegateが必要。面倒くさい。 */
this.tmr = new Timer();
this.tmr.Tick += new EventHandler( this.timer_Tick);
this.tmr.Interval = 100;
this.tmr.Enabled = false;
/*--------------------------------------------------*/
this.ResumeLayout();
}
/*--------------------------------------------------*/
private void CreateMenu()
{
this.ms = new MenuStrip();
this.tsmi = new ToolStripMenuItem[2][];
this.tsmi[0] = new ToolStripMenuItem[4];
this.tsmi[1] = new ToolStripMenuItem[5];
for( int i = 0; i < this.tsmi.Length; i++)
{
this.tsmi[i][0] = new ToolStripMenuItem();
this.ms.Items.Add( this.tsmi[i][0]);
for( int j = 1; j < this.tsmi[i].Length; j++)
{
this.tsmi[i][j] = new ToolStripMenuItem();
this.tsmi[i][j].Click += new EventHandler( this.Menu_Click);
this.tsmi[i][0].DropDownItems.Add( this.tsmi[i][j]);
}
}
this.tsmi[0][0].Text = "File (&F)";
this.tsmi[0][1].Text = "Open (&O)";
this.tsmi[0][2].Text = "Close (&C)";
this.tsmi[0][3].Text = "Exit (&X)";
this.tsmi[1][0].Text = "Midi (&M)";
this.tsmi[1][1].Text = "TimeDivision";
this.tsmi[1][2].Text = "Play";
this.tsmi[1][3].Text = "Play Track";
this.tsmi[1][4].Text = "Stop";
this.Controls.Add( this.ms);
this.MainMenuStrip = ms;
}
private void Menu_Click( object sender, EventArgs e)
{
if( sender == this.tsmi[0][1])
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "file|*.mid";
if( ofd.ShowDialog() == DialogResult.OK)
{
this.open( ofd.FileName);
}
}
else if( sender == this.tsmi[0][2])
{
this.player.Stop();
this.tmr.Enabled = false;
this.cbx.Items.Clear();
this.lbx.Items.Clear();
this.TimeDivision = 0;
this.Track = null;
}
else if( sender == this.tsmi[0][3])
{
this.Close();
}
else if( sender == this.tsmi[1][1])
{
MessageBox.Show( "TimeDivision : " + this.TimeDivision.ToString() + " tick");
}
else if( sender == this.tsmi[1][2])
{
if( this.Track == null)
{
return;
}
int i = this.cbx.SelectedIndex;
int j = this.lbx.SelectedIndex;
int tm = this.Track[i][j].Time * 500 / this.TimeDivision;
this.player.Play( this.TimeDivision, this.Track, tm);
this.tmr.Enabled = true;
}
else if( sender == this.tsmi[1][3])
{
if( this.Track == null)
{
return;
}
int i = this.cbx.SelectedIndex;
int j = this.lbx.SelectedIndex;
int tm = this.Track[i][j].Time * 500 / this.TimeDivision;
this.trk = new MidiEvent[1][];
this.trk[0] = new MidiEvent[this.Track[i].Length];
for( int k = 0; k < this.trk[0].Length; k++)
{
this.trk[0][k] = this.Track[i][k];
}
this.player.Play( this.TimeDivision, this.trk, tm);
this.tmr.Enabled = true;
}
else if( sender == this.tsmi[1][4])
{
if( this.Track == null)
{
return;
}
this.player.Stop();
this.tmr.Enabled = false;
}
}
/*--------------------------------------------------*/
private void Form_Load( object sender, EventArgs e)
{
Console.WriteLine( "Form_Load");
this.player = new MidiPlayer();
/*--------------------------------------------------*/
string[] args = Environment.GetCommandLineArgs();
if( 1 < args.Length)
{
this.open( args[1]);
}
}
private void Form_FormClosed( object sender, EventArgs e)
{
Console.WriteLine( "Form_FormClosed");
this.player.Stop();
this.tmr.Enabled = false;
}
/*--------------------------------------------------*/
private void Form_DragEnter( object sender, DragEventArgs e)
{
if( e.Data.GetDataPresent( DataFormats.FileDrop))
{
e.Effect = DragDropEffects.Move;
}
}
private void Form_DragDrop( object sender, DragEventArgs e)
{
Console.WriteLine( "Form_DragDrop");
string[] filename = (string[]) e.Data.GetData( DataFormats.FileDrop, false);
this.open( filename[0]);
}
/*--------------------------------------------------*/
private void cbx_SelectedIndexChanged( object sender, EventArgs e)
{
Console.WriteLine( "cbx_SelectedIndexChanged");
this.lbx.Items.Clear();
int index = this.cbx.SelectedIndex;
for( int i = 0; i < this.Track[index].Length; i++)
{
byte evt = this.Track[index][i].Event;
string str = i.ToString() + "\t";
str += this.Track[index][i].Time.ToString() + "\t";
str += this.Track[index][i].Event.ToString( "x") + "\t";
if( evt < 0xf0)
{
ChannelEvent ce = (ChannelEvent) this.Track[index][i];
str += ce.Param1.ToString() + "\t";
str += ce.Param2.ToString() + "\t";
str += "\t";
str += "\t";
}
else if( evt == 0xf0 || evt == 0xf7)
{
SystemEvent se = (SystemEvent) this.Track[index][i];
str += "\t";
str += "\t";
str += "\t";
str += se.Data.Length.ToString() + "\t";
}
else if( evt == 0xff)
{
MetaEvent me = (MetaEvent) this.Track[index][i];
str += "\t";
str += "\t";
str += me.Type.ToString() + "\t";
str += me.Data.Length.ToString() + "\t";
}
this.lbx.Items.Add( str);
}
this.lbx.SelectedIndex = 0;
}
/*--------------------------------------------------*/
private void timer_Tick( object sender, EventArgs e)
{
/*--------------------------------------------------*/
if( this.player.IsPlaying() == false)
{
this.tmr.Enabled = false;
return;
}
/*--------------------------------------------------*/
long tm = this.player.PlayTime;
int index = this.cbx.SelectedIndex;
int first = 0;
int last = this.Track[index].Length - 1;
while( 1 < last - first)
{
int next = ( first + last) / 2;
if( this.Track[index][next].Time * 500 / this.TimeDivision < tm)
{
first = next;
}
else
{
last = next;
}
}
if( first < this.lbx.Items.Count)
{
// cbxの選択が変更されると、Play中でもlbxが一度Clearされる
// そのため、このif文がないとタイミングによってエラーになる
this.lbx.SelectedIndex = first;
}
}
/*--------------------------------------------------*/
private void open( string filename)
{
this.player.Stop();
this.tmr.Enabled = false;
/*--------------------------------------------------*/
try
{
MidiFileReader.Read( filename, ref this.TimeDivision, ref this.Track);
}
catch( Exception e)
{
MessageBox.Show( "File Read Error");
Console.WriteLine( e.ToString());
}
/*--------------------------------------------------*/
this.cbx.Items.Clear();
for( int i = 0; i < this.Track.Length; i++)
{
this.cbx.Items.Add( "Track " + i.ToString());
}
this.cbx.SelectedIndex = 0;
}
}
0 件のコメント:
コメントを投稿