前回はmciSendString関数を色々試したので、今回はそれを使って簡単なMusic Playerを作ります。ソースコードは530行だけなので簡単です。
今回のソフトを作るときに一番苦労したのはUIのデザインです。
最初は、曲を移動するための"Next"、"Prev"ボタンとか、リストから1曲削除するボタンとか、"Pause/Resume"機能とかも作ったのですが、結局、やめました。とにかく単純にしたかったから。
ちなみに、音量操作をトラックバーではなく、ボタンにしたのは、見た目が理由です。トラックバーだと、再生位置用のトラックバーとかぶるんで。
リストの保存とか、ファイルの拡張子の制限とか、ほかにも機能は色々追加できるんですが。まぁ、なくてもいいかなぁ、という感じです。
結果、コンパイルしたら12KBでした。こういう軽いソフトが好きなんです。
ソースコードはご自由にご利用ください。ただし、趣味のプログラムなので保証はありません。
using System;
using System.IO;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Collections.Generic;
/*--------------------------------------------------*/
class Program
{
[STAThread]
static void Main()
{
Application.Run( new MusicPlayer());
}
}
/*--------------------------------------------------*/
class MusicPlayer : Form
{
/*--------------------------------------------------*/
[DllImport( "Winmm.dll")]
extern static int mciSendString( string cmd, System.Text.StringBuilder retStr, uint ret, IntPtr hwnd);
/*--------------------------------------------------*/
private MenuStrip ms;
private ToolStripMenuItem[][] tsmi;
private Label lbl;
private ListBox lbx;
private List<string> lst;
private TextBox tbx;
private TrackBar tbr;
private Button[] btn;
private const string DeviceID = "mysound";
private int volume;
private Timer tmr;
/*--------------------------------------------------*/
public MusicPlayer()
{
/*--------------------------------------------------*/
this.ClientSize = new Size( 280, 360);
this.Text = "Music Player";
this.Load += new EventHandler( this.Form_Load);
this.Closed += new EventHandler( this.Form_Closed);
this.AllowDrop = true;
this.DragEnter += new DragEventHandler( this.Form_DragEnter);
this.DragDrop += new DragEventHandler( this.Form_DragDrop);
/*--------------------------------------------------*/
this.CreateMenu();
/*--------------------------------------------------*/
this.lbl = new Label();
this.lbl.SetBounds( 20, 30, 240, 30);
this.lbl.Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right;
this.lbl.TextAlign = ContentAlignment.MiddleLeft;
this.lbl.Text = "Play List";
this.Controls.Add( this.lbl);
/*--------------------------------------------------*/
this.lbx = new ListBox();
this.lbx.SetBounds( 20, 60, 240, 160);
this.lbx.Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom;
this.lbx.HorizontalScrollbar = true;
this.Controls.Add( this.lbx);
/*--------------------------------------------------*/
this.tbx = new TextBox();
this.tbx.SetBounds( 20, 230, 240, 20);
this.tbx.Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom;
this.tbx.BorderStyle = BorderStyle.None;
this.tbx.ReadOnly = true;
this.Controls.Add( this.tbx);
this.tbr = new TrackBar();
this.tbr.SetBounds( 20, 250, 240, 50);
this.tbr.Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom;
this.tbr.MouseUp += new MouseEventHandler( this.tbr_MouseUp);
this.Controls.Add( this.tbr);
/*--------------------------------------------------*/
this.btn = new Button[4];
this.btn[0] = new Button();
this.btn[0].SetBounds( 20, 300, 60, 40);
this.btn[0].Anchor = AnchorStyles.Bottom;
this.btn[0].Text = ">";
this.btn[0].Click += new EventHandler( this.btn_Play_Click);
this.Controls.Add( this.btn[0]);
this.btn[1] = new Button();
this.btn[1].SetBounds( 80, 300, 60, 40);
this.btn[1].Anchor = AnchorStyles.Bottom;
this.btn[1].Text = "||";
this.btn[1].Click += new EventHandler( this.btn_Stop_Click);
this.Controls.Add( this.btn[1]);
this.btn[2] = new Button();
this.btn[2].SetBounds( 140, 300, 60, 40);
this.btn[2].Anchor = AnchorStyles.Bottom;
this.btn[2].Text = "Vol.-";
this.btn[2].Click += new EventHandler( this.btn_VolumeDown_Click);
this.Controls.Add( this.btn[2]);
this.btn[3] = new Button();
this.btn[3].SetBounds( 200, 300, 60, 40);
this.btn[3].Anchor = AnchorStyles.Bottom;
this.btn[3].Text = "Vol.+";
this.btn[3].Click += new EventHandler( this.btn_VolumeUp_Click);
this.Controls.Add( this.btn[3]);
}
/*--------------------------------------------------*/
private void Form_Load( object sender, EventArgs e)
{
Console.WriteLine( "Form_Load");
this.lst = new List<string>();
this.volume = 10;
this.tmr = new Timer();
this.tmr.Interval = 1000;
this.tmr.Tick += new EventHandler( this.timer_Tick);
}
private void Form_Closed( object sender, EventArgs e)
{
Console.WriteLine( "Form_Closed");
this.tmr.Enabled = false;
string cmd = "stop " + MusicPlayer.DeviceID;
int ret = mciSendString( cmd, null, 0, IntPtr.Zero);
Console.WriteLine( cmd);
cmd = "close " + MusicPlayer.DeviceID;
ret = mciSendString( cmd, null, 0, IntPtr.Zero);
Console.WriteLine( cmd);
}
/*--------------------------------------------------*/
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)
{
string[] filenames = (string[]) e.Data.GetData( DataFormats.FileDrop, false);
this.lbx_Add( filenames);
}
/*--------------------------------------------------*/
private void CreateMenu()
{
this.ms = new MenuStrip();
this.tsmi = new ToolStripMenuItem[2][];
this.tsmi[0] = new ToolStripMenuItem[4];
this.tsmi[1] = new ToolStripMenuItem[3];
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";
this.tsmi[0][1].Text = "Select";
this.tsmi[0][2].Text = "Clear";
this.tsmi[0][3].Text = "Exit (&X)";
this.tsmi[1][0].Text = "MCI";
this.tsmi[1][1].Text = "Play";
this.tsmi[1][2].Text = "Stop";
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;
}
/*--------------------------------------------------*/
/* Menuのイベント処理 */
/*--------------------------------------------------*/
private void Menu_Click( object sender, EventArgs e)
{
Console.WriteLine( sender.ToString());
if( sender == this.tsmi[0][1])
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "All files | *.*";
ofd.Multiselect = true;
if( ofd.ShowDialog() == DialogResult.OK)
{
this.lbx_Add( ofd.FileNames);
}
}
else if( sender == this.tsmi[0][2])
{
this.lbx_Clear();
}
else if( sender == this.tsmi[0][3])
{
this.Close();
}
else if( sender == this.tsmi[1][1])
{
this.btn_Play_Click( null, null);
}
else if( sender == this.tsmi[1][2])
{
this.btn_Stop_Click( null, null);
}
}
/*--------------------------------------------------*/
/* リストの処理 */
/*--------------------------------------------------*/
private void lbx_Add( string[] filenames)
{
for( int i = 0; i < filenames.Length; i++)
{
Console.WriteLine( filenames[i]);
this.lst.Add( filenames[i]);
this.lbx.Items.Add( Path.GetFileName( filenames[i]));
this.lbx.SelectedIndex = this.lbx.Items.Count - 1;
}
}
private void lbx_Clear()
{
this.lst.Clear();
this.lbx.Items.Clear();
}
/*--------------------------------------------------*/
/* Buttonのイベント処理 */
/*--------------------------------------------------*/
private void btn_Play_Click( object sender, EventArgs e)
{
Console.WriteLine( "btn_Play_Click");
string status = this.mciGetStatus();
if( status == "")
{
if( this.lbx.SelectedIndex == -1)
{
return;
}
this.mciOpen( this.lst[this.lbx.SelectedIndex]);
this.mciPlay();
}
else if( status == "playing")
{
return;
}
else if( status == "stopped")
{
this.mciPlay();
}
}
private void btn_Stop_Click( object sender, EventArgs e)
{
Console.WriteLine( "btn_Stop_Click");
string status = this.mciGetStatus();
if( status == "")
{
return;
}
else if( status == "playing")
{
this.mciStop();
}
else if( status == "stopped")
{
this.mciClose();
}
}
private void btn_VolumeDown_Click( object sender, EventArgs e)
{
Console.WriteLine( "btn_VolumeDown_Click");
string status = this.mciGetStatus();
if( status != "")
{
this.mciVolumeDown();
}
}
private void btn_VolumeUp_Click( object sender, EventArgs e)
{
Console.WriteLine( "btn_VolumeUp_Click");
string status = this.mciGetStatus();
if( status != "")
{
this.mciVolumeUp();
}
}
/*--------------------------------------------------*/
/* TrackBarのイベント処理 */
/*--------------------------------------------------*/
private void tbr_MouseUp( object sender, MouseEventArgs e)
{
Console.WriteLine( "tbr_MouseUp");
string status = this.mciGetStatus();
if( status != "")
{
this.tmr.Enabled = false;
this.mciSeek( this.tbr.Value);
}
}
/*--------------------------------------------------*/
/* 再生中のタイマーイベント */
/*--------------------------------------------------*/
private void timer_Tick( object sender, EventArgs e)
{
Console.WriteLine( "timer tick");
/*--------------------------------------------------*/
string str = this.mciGetStatus();
/*--------------------------------------------------*/
StringBuilder retStr = new StringBuilder( 256);
string cmd = "status " + MusicPlayer.DeviceID + " position";
int ret = mciSendString( cmd, retStr, (uint) retStr.Capacity, IntPtr.Zero);
str += ", pos.:" + retStr.ToString();
this.tbr.Value = Convert.ToInt32( retStr.ToString());
cmd = "status " + MusicPlayer.DeviceID + " length";
ret = mciSendString( cmd, retStr, (uint) retStr.Capacity, IntPtr.Zero);
str += " / " + retStr.ToString();
/*--------------------------------------------------*/
cmd = "status " + MusicPlayer.DeviceID + " volume";
ret = mciSendString( cmd, retStr, (uint) retStr.Capacity, IntPtr.Zero);
str += ", vol.:" + retStr.ToString();
/*--------------------------------------------------*/
this.tbx.Text = str;
}
/*--------------------------------------------------*/
/* Notifyイベントの処理 */
/* 曲が終わったら、リストの次の曲を再生する (Stop or Seekから呼ばれた場合はreturn)
/*--------------------------------------------------*/
protected override void WndProc( ref Message m)
{
base.WndProc( ref m);
if( m.Msg == 0x03B9) //MM_MCINOTIFY message
{
Console.WriteLine( "Notify");
if( this.tmr.Enabled == false)
{
return;
}
this.mciStop();
this.mciClose();
if( ! ( 0 <= this.lbx.SelectedIndex && this.lbx.SelectedIndex < this.lbx.Items.Count - 1))
{
return;
}
this.lbx.SelectedIndex++;
this.mciOpen( this.lst[this.lbx.SelectedIndex]);
this.mciPlay();
}
}
/*--------------------------------------------------*/
/* MCIの状態を返す ("", "playing", "stopped"のいずれかになるはず) */
/*--------------------------------------------------*/
private string mciGetStatus()
{
StringBuilder retStr = new StringBuilder( 256);
string cmd = "status " + MusicPlayer.DeviceID + " mode";
int ret = mciSendString( cmd, retStr, (uint) retStr.Capacity, IntPtr.Zero);
Console.WriteLine( "mode : " + retStr);
return retStr.ToString();
}
/*--------------------------------------------------*/
/* MCI Open, Play, Stop, Close */
/*--------------------------------------------------*/
private void mciOpen( string filename)
{
/*--------------------------------------------------*/
string cmd = "open " + "\"" + filename + "\"" + " alias " + MusicPlayer.DeviceID;
int ret = mciSendString( cmd, null, 0, IntPtr.Zero);
Console.WriteLine( cmd);
/*--------------------------------------------------*/
cmd = "setaudio " + MusicPlayer.DeviceID + " volume to " + ( this.volume * 100).ToString();
ret = mciSendString( cmd, null, 0, IntPtr.Zero);
Console.WriteLine( cmd);
/*--------------------------------------------------*/
StringBuilder retStr = new StringBuilder( 256);
cmd = "status " + MusicPlayer.DeviceID + " length";
ret = mciSendString( cmd, retStr, (uint) retStr.Capacity, IntPtr.Zero);
this.tbr.Minimum = 0;
this.tbr.Maximum = Convert.ToInt32( retStr.ToString());
}
private void mciPlay()
{
string cmd = "play " + MusicPlayer.DeviceID + " notify";
int ret = mciSendString( cmd, null, 0, this.Handle);
Console.WriteLine( cmd);
this.tmr.Enabled = true;
this.timer_Tick( null, null);
}
private void mciStop()
{
this.tmr.Enabled = false;
string cmd = "stop " + MusicPlayer.DeviceID;
int ret = mciSendString( cmd, null, 0, IntPtr.Zero);
Console.WriteLine( cmd);
this.timer_Tick( null, null);
}
private void mciClose()
{
string cmd = "close " + MusicPlayer.DeviceID;
int ret = mciSendString( cmd, null, 0, IntPtr.Zero);
Console.WriteLine( cmd);
this.tbx.Text = "";
}
/*--------------------------------------------------*/
/* MCI Volume Down/Up */
/*--------------------------------------------------*/
private void mciVolumeDown()
{
this.volume = Math.Max( 0, this.volume - 1);
string cmd = "setaudio " + MusicPlayer.DeviceID + " volume to " + ( this.volume * 100).ToString();
int ret = mciSendString( cmd, null, 0, IntPtr.Zero);
Console.WriteLine( cmd);
this.timer_Tick( null, null);
}
private void mciVolumeUp()
{
this.volume = Math.Min( this.volume + 1, 10);
string cmd = "setaudio " + MusicPlayer.DeviceID + " volume to " + ( this.volume * 100).ToString();
int ret = mciSendString( cmd, null, 0, IntPtr.Zero);
Console.WriteLine( cmd);
this.timer_Tick( null, null);
}
/*--------------------------------------------------*/
/* MCI Seek */
/*--------------------------------------------------*/
private void mciSeek( int position)
{
string cmd = "seek " + MusicPlayer.DeviceID + " to " + position.ToString();
int ret = mciSendString( cmd, null, 0, IntPtr.Zero);
Console.WriteLine( cmd);
this.timer_Tick( null, null);
}
}