此项目需求是针对.wav格式音频进行操作,转换成相应的.mp3格式的音频文件,对音频进行切割,最后以需求的形式输出,此篇会回顾运用到的一些知识点。
1.MDI子窗口的建立:
首先一个窗体能够创建多个MDI窗体,应当将IsMDIContainer属性设为true;以下为效果图:
控制窗体切换的是一个DotNetBar.TabStrip控件,style属性为Office2007Document,TabLayOutType:FixedWithNavigationBox
创建窗体的代码如下:
01 |
/// <summary> |
02 |
/// 创建MDI子窗体类
|
03 |
/// </summary>
|
04 |
classCreateMDIWindow
|
05 |
{
|
06 |
/// <summary>
|
07 |
/// 当前程序的主窗体对象
|
08 |
/// </summary>
|
09 |
public staticForm MainForm { get; set; }
|
10 |
|
11 |
/// <summary>
|
12 |
/// 创建子窗口
|
13 |
/// </summary>
|
14 |
///
|
15 |
<typeparam name="T"> 窗口类型
|
16 |
</typeparam> |
17 |
public static void CreateChildWindow
|
18 |
<t> () where T : Form, new()
|
19 |
// where 子句还可以包括构造函数约束。 可以使用 new 运算符创建类型参数的实例;但类型参数为此必须受构造函数约束
|
20 |
// new() 的约束。 new() 约束可以让编译器知道:提供的任何类型参数都必须具有可访问的无参数(或默认)构造函数。
|
21 |
{
|
22 |
T form = null;
|
23 |
|
24 |
var childForms = MainForm.MdiChildren;
|
25 |
//遍历窗体
|
26 |
foreach (Form f inchildForms)
|
27 |
{
|
28 |
if (f isT)
|
29 |
{
|
30 |
form = f asT;
|
31 |
break;
|
32 |
}
|
33 |
}
|
34 |
//如果没有,则创建
|
35 |
if(form == null)
|
36 |
{
|
37 |
//新建窗体
|
38 |
form = newT();
|
39 |
//设定窗体的图标
|
40 |
form.Icon = System.Drawing.Icon.FromHandle(Properties.Resources.MainIcon.GetHicon());
|
41 |
//设定窗体的主图标
|
42 |
form.MdiParent = MainForm;
|
43 |
//设定窗体的边框类型
|
44 |
form.FormBorderStyle = FormBorderStyle.FixedToolWindow;
|
45 |
}
|
46 |
//窗口如何显示
|
47 |
form.WindowState = FormWindowState.Maximized;
|
48 |
form.Show();
|
49 |
}
|
50 |
}
|
51 |
</t> |
前台点击按钮调用代码:CreateMDIWindow.CreateChildWindow (); <>里为窗体的名称。
2.序列化与反序列化:
当一个系统你有默认的工作目录,默认的文件保存路径,且这些数据时唯一的,你希望每次打开软件都会显示这些数据,也可以更新这些数据,可以使用序列化与反序列化。
我们以项目存储根目录和选择项目为例:
代码如下:
01 |
[Serializable] |
02 |
public classUserSetting
|
03 |
{ |
04 |
/// <summary>
|
05 |
/// 序列化存储路径
|
06 |
/// </summary>
|
07 |
private string FilePath{ get { returnPath.Combine(Environment.CurrentDirectory, "User.data"); } }
|
08 |
|
09 |
/// <summary>
|
10 |
/// 音频资源存储目录
|
11 |
/// </summary>
|
12 |
public stringAudioResourceFolder { get; set; }
|
13 |
|
14 |
/// <summary>
|
15 |
/// 项目名称
|
16 |
/// </summary>
|
17 |
public stringSolution { get; set; }
|
18 |
|
19 |
/// <summary>
|
20 |
/// 构造函数,创建序列化存储文件
|
21 |
/// </summary>
|
22 |
publicUserSetting()
|
23 |
{
|
24 |
if(!File.Exists(FilePath))
|
25 |
{
|
26 |
FileStream fs = File.Create(FilePath);
|
27 |
fs.Close();//不关闭文件流,首次创建该文件后不能被使用买现成会被占用
|
28 |
}
|
29 |
}
|
30 |
|
31 |
/// <summary>
|
32 |
/// 通过反序列化方法,获得保存的数据
|
33 |
/// </summary>
|
34 |
publicUserSetting ReadUserSetting()
|
35 |
{
|
36 |
using (FileStream fs = newFileStream(FilePath, FileMode.Open,FileAccess.Read))
|
37 |
{
|
38 |
objectob = null;
|
39 |
if(fs.Length > 0)
|
40 |
{
|
41 |
SoapFormatter sf = newSoapFormatter();
|
42 |
ob = sf.Deserialize(fs);
|
43 |
}
|
44 |
return ob asUserSetting;
|
45 |
}
|
46 |
}
|
47 |
|
48 |
/// <summary>
|
49 |
/// 通过序列化方式,保存数据
|
50 |
/// </summary>
|
51 |
public void SaveUserSetting(objectobj)
|
52 |
{
|
53 |
using (FileStream fs = newFileStream(FilePath, FileMode.OpenOrCreate, FileAccess.Write))
|
54 |
{
|
55 |
SoapFormatter sf = newSoapFormatter();
|
56 |
sf.Serialize(fs,obj);
|
57 |
}
|
58 |
}
|
59 |
|
60 |
} |
3.Datagridview动态生成:
根据设置的楼层生成相应楼层带button按钮的datagridview,并且每层按钮为每层选定选择音乐,代码如下:
01 |
/// <summary> |
02 |
/// 绑定楼层音乐属性 |
03 |
/// </summary> |
04 |
private void BindData(int elevatorLow,intnumber)
|
05 |
{ |
06 |
try |
07 |
{
|
08 |
DataTable list = newDataTable();
|
09 |
list.Columns.Clear();
|
10 |
list.Columns.Add(newDataColumn("name", typeof(string)));
|
11 |
list.Columns.Add(newDataColumn("musicPath", typeof(string)));
|
12 |
for (inti =0; i < number; i++)
|
13 |
{
|
14 |
//不包括楼层0层
|
15 |
if(elevatorLow != 0)
|
16 |
{
|
17 |
list.Rows.Add(list.NewRow());
|
18 |
list.Rows[i][0] = elevatorLow;
|
19 |
}
|
20 |
else{ i--; }
|
21 |
elevatorLow++;
|
22 |
}
|
23 |
dataGridViewX1.DataSource = list;
|
24 |
}
|
25 |
catch(Exception ex)
|
26 |
{ MessageBox.Show(ex.ToString()); }
|
27 |
} |
选择音乐按钮事件:
01 |
private void dataGridViewX1_CellContentClick(objectsender, DataGridViewCellEventArgs e)
|
02 |
{ |
03 |
try |
04 |
{
|
05 |
//点击选择按钮触发的事件
|
06 |
if(e.RowIndex >= 0)
|
07 |
{
|
08 |
DataGridViewColumn column = dataGridViewX1.Columns[e.ColumnIndex];
|
09 |
if (column isDataGridViewButtonColumn)
|
10 |
{
|
11 |
OpenFileDialog openMusic = newOpenFileDialog();
|
12 |
openMusic.AddExtension = true;
|
13 |
openMusic.Multiselect = true;
|
14 |
openMusic.Filter = "MP3文件(*.mp3)|*mp3";
|
15 |
if(openMusic.ShowDialog() == DialogResult.OK)
|
16 |
{
|
17 |
dataGridViewX1.Rows[e.RowIndex].Cells[2].Value = Path.GetFileName(openMusic.FileName);
|
18 |
}
|
19 |
}
|
20 |
}
|
21 |
}
|
22 |
catch(Exception ex)
|
23 |
{ MessageBox.Show(ex.ToString()); }
|
24 |
} |
4.获得音乐文件属性:
使用Shellclass获得文件属性可以参考 点击打开链接
代码如下:
01 |
/// <summary> |
02 |
/// 获得音乐长度 |
03 |
/// </summary> |
04 |
/// <param name="filePath">文件的完整路径 |
05 |
public static string[] GetMP3Time(stringfilePath)
|
06 |
{ |
07 |
stringdirName = Path.GetDirectoryName(filePath);
|
08 |
stringSongName = Path.GetFileName(filePath);//获得歌曲名称
|
09 |
ShellClass sh = newShellClass();
|
10 |
Folder dir = sh.NameSpace(dirName);
|
11 |
FolderItem item = dir.ParseName(SongName);
|
12 |
stringSongTime = dir.GetDetailsOf(item, 27);//27为获得歌曲持续时间 ,28为获得音乐速率,1为获得音乐文件大小
|
13 |
string[] time = Regex.Split(SongTime, ":");
|
14 |
returntime;
|
15 |
} |
5.音频操作:
音频的操作用的fmpeg.exe ,下载地址
fmpeg放在bin目录下,代码如下:
01 |
/// <summary> |
02 |
/// 转换函数 |
03 |
/// </summary> |
04 |
/// <param name="exe">ffmpeg程序 |
05 |
/// <param name="arg">执行参数 |
06 |
public static void ExcuteProcess(string exe, stringarg)
|
07 |
{ |
08 |
using (var p = newProcess())
|
09 |
{
|
10 |
p.StartInfo.FileName = exe;
|
11 |
p.StartInfo.Arguments = arg;
|
12 |
p.StartInfo.UseShellExecute = false; //输出信息重定向
|
13 |
p.StartInfo.CreateNoWindow = true;
|
14 |
p.StartInfo.RedirectStandardError = true;
|
15 |
p.StartInfo.RedirectStandardOutput = true;
|
16 |
p.Start(); //启动线程
|
17 |
p.BeginOutputReadLine();
|
18 |
p.BeginErrorReadLine();
|
19 |
p.WaitForExit();//等待进程结束
|
20 |
}
|
21 |
} |
音频转换的代码如下:
01 |
private void btnConvert_Click(objectsender, EventArgs e)
|
02 |
{ |
03 |
//转换MP3
|
04 |
if(txtMp3Music.Text != "")
|
05 |
{
|
06 |
string fromMusic = Statics.Setting.AudioResourceFolder + "\\"+ Statics.Setting.Solution+"\\" + cobFolders.Text + "\\" + txtMusic.Text;//转换音乐路径
|
07 |
string toMusic = Statics.Setting.AudioResourceFolder + "\\"+ Statics.Setting.Solution+"\\" + cobFolders.Text + "\\"+ txtMp3Music.Text;//转换后音乐路径
|
08 |
intbitrate = Convert.ToInt32(cobBitRate.Text) * 1000;//恒定码率
|
09 |
stringHz = cobHz.Text;//采样频率
|
10 |
|
11 |
try |
12 |
{
|
13 |
MP3Convertion.ExcuteProcess("ffmpeg.exe", "-y -ab " + bitrate + " -ar "+ Hz + " -i \"" + fromMusic + "\" \"" + toMusic + "\"");
|
14 |
if(cbRetain.Checked == false)
|
15 |
{
|
16 |
File.Delete(fromMusic);
|
17 |
BindList();
|
18 |
}
|
19 |
else |
20 |
{
|
21 |
foreach (ListViewItem lt inlistMusics.Items)
|
22 |
{
|
23 |
if(lt.Text == txtMusic.Text)
|
24 |
{
|
25 |
listMusics.Items.Remove(lt);
|
26 |
}
|
27 |
}
|
28 |
}
|
29 |
|
30 |
//转换完成
|
31 |
MessageBox.Show("转换完成");
|
32 |
txtMusic.Text = "";
|
33 |
txtMp3Music.Text = "";
|
34 |
}
|
35 |
catch(Exception ex)
|
36 |
{ MessageBox.Show(ex.ToString()); }
|
37 |
}
|
38 |
else |
39 |
{
|
40 |
MessageBox.Show("请选择你要转换的音乐");
|
41 |
}
|
42 |
} |
音频切割的代码如下:
01 |
private void btnCut_Click(objectsender, EventArgs e)
|
02 |
{ |
03 |
SaveFileDialog saveMusic = newSaveFileDialog();
|
04 |
saveMusic.Title = "选择音乐文件存放的位置";
|
05 |
saveMusic.DefaultExt = ".mp3";
|
06 |
saveMusic.InitialDirectory = Statics.Setting.AudioResourceFolder +"\\" + Statics.Setting.Solution+"\\" + cobFolders.Text;
|
07 |
string fromPath = Statics.Setting.AudioResourceFolder + "\\"+ Statics.Setting.Solution +"\\"+ cobFolders.Text + "\\"+ txtMusic.Text;//要切割音乐的物理路径
|
08 |
stringstartTime = string.Format("0:{0}:{1}", txtBeginM.Text, txtBeginS.Text).Trim();//歌曲起始时间
|
09 |
intduration = (Convert.ToInt32(this.txtEndM.Text) * 60 + Convert.ToInt32(this.txtEndS.Text)) - (Convert.ToInt32(this.txtBeginM.Text) * 60 + Convert.ToInt32(this.txtBeginS.Text));
|
10 |
stringendTime = string.Format("0:{0}:{1}", duration / 60, duration % 60);//endTime是持续的时间,不是歌曲结束的时间
|
11 |
if(saveMusic.ShowDialog() == DialogResult.OK)
|
12 |
{
|
13 |
stringsavePath = saveMusic.FileName;//切割后音乐保存的物理路径
|
14 |
try |
15 |
{
|
16 |
MP3Convertion.ExcuteProcess("ffmpeg.exe", "-y -i \"" + fromPath + "\" -ss "+ startTime + " -t " + endTime + " -acodec copy \""+ savePath+"\"");//-acodec copy表示歌曲的码率和采样频率均与前者相同
|
17 |
MessageBox.Show("已切割完成");
|
18 |
}
|
19 |
catch(Exception ex)
|
20 |
{
|
21 |
MessageBox.Show(ex.ToString());
|
22 |
}
|
23 |
}
|
24 |
} |
切割音频操作系统的知识点就总结道这了,就是fmpeg的应用。