.Net操作音频
请选中您要保存的内容,粘贴到此文本框
此项目需求是针对.wav格式音频进行操作,转换成相应的.mp3格式的音频文件,对音频进行切割,最后以需求的形式输出,此篇会回顾运用到的一些知识点。
1.MDI子窗口的建立:
首先一个窗体能够创建多个MDI窗体,应当将IsMDIContainer属性设为true;以下为效果图:
控制窗体切换的是一个DotNetBar.TabStrip控件,style属性为Office2007Document,TabLayOutType:FixedWithNavigationBox
创建窗体的代码如下:
01 |
/// <SUMMARY> |
02 |
/// 创建MDI子窗体类 |
03 |
/// </SUMMARY> |
04 |
class CreateMDIWindow |
05 |
{ |
06 |
/// <SUMMARY> |
07 |
/// 当前程序的主窗体对象 |
08 |
/// </SUMMARY> |
09 |
public static Form 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 in childForms) |
27 |
{ |
28 |
if (f is T) |
29 |
{ |
30 |
form = f as T; |
31 |
break ; |
32 |
} |
33 |
} |
34 |
//如果没有,则创建 |
35 |
if (form == null ) |
36 |
{ |
37 |
//新建窗体 |
38 |
form = new T(); |
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 class UserSetting |
03 |
{ |
04 |
/// <SUMMARY> |
05 |
/// 序列化存储路径 |
06 |
/// </SUMMARY> |
07 |
private string FilePath{ get { return Path.Combine(Environment.CurrentDirectory, "User.data" ); } } |
08 |
|
09 |
/// <SUMMARY> |
10 |
/// 音频资源存储目录 |
11 |
/// </SUMMARY> |
12 |
public string AudioResourceFolder { get ; set ; } |
13 |
|
14 |
/// <SUMMARY> |
15 |
/// 项目名称 |
16 |
/// </SUMMARY> |
17 |
public string Solution { get ; set ; } |
18 |
|
19 |
/// <SUMMARY> |
20 |
/// 构造函数,创建序列化存储文件 |
21 |
/// </SUMMARY> |
22 |
public UserSetting() |
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 |
public UserSetting ReadUserSetting() |
35 |
{ |
36 |
using (FileStream fs = new FileStream(FilePath, FileMode.Open,FileAccess.Read)) |
37 |
{ |
38 |
object ob = null ; |
39 |
if (fs.Length > 0) |
40 |
{ |
41 |
SoapFormatter sf = new SoapFormatter(); |
42 |
ob = sf.Deserialize(fs); |
43 |
} |
44 |
return ob as UserSetting; |
45 |
} |
46 |
} |
47 |
|
48 |
/// <SUMMARY> |
49 |
/// 通过序列化方式,保存数据 |
50 |
/// </SUMMARY> |
51 |
public void SaveUserSetting( object obj) |
52 |
{ |
53 |
using (FileStream fs = new FileStream(FilePath, FileMode.OpenOrCreate, FileAccess.Write)) |
54 |
{ |
55 |
SoapFormatter sf = new SoapFormatter(); |
56 |
sf.Serialize(fs,obj); |
57 |
} |
58 |
} |
59 |
|
60 |
} |
3.Datagridview动态生成:
根据设置的楼层生成相应楼层带button按钮的datagridview,并且每层按钮为每层选定选择音乐,代码如下:
01 |
/// <SUMMARY> |
02 |
/// 绑定楼层音乐属性 |
03 |
/// </SUMMARY> |
04 |
private void BindData( int elevatorLow, int number) |
05 |
{ |
06 |
try |
07 |
{ |
08 |
DataTable list = new DataTable(); |
09 |
list.Columns.Clear(); |
10 |
list.Columns.Add( new DataColumn( "name" , typeof ( string ))); |
11 |
list.Columns.Add( new DataColumn( "musicPath" , typeof ( string ))); |
12 |
for ( int i =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( object sender, DataGridViewCellEventArgs e) |
02 |
{ |
03 |
try |
04 |
{ |
05 |
//点击选择按钮触发的事件 |
06 |
if (e.RowIndex >= 0) |
07 |
{ |
08 |
DataGridViewColumn column = dataGridViewX1.Columns[e.ColumnIndex]; |
09 |
if (column is DataGridViewButtonColumn) |
10 |
{ |
11 |
OpenFileDialog openMusic = new OpenFileDialog(); |
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( string filePath) |
06 |
{ |
07 |
string dirName = Path.GetDirectoryName(filePath); |
08 |
string SongName = Path.GetFileName(filePath); //获得歌曲名称 |
09 |
ShellClass sh = new ShellClass(); |
10 |
Folder dir = sh.NameSpace(dirName); |
11 |
FolderItem item = dir.ParseName(SongName); |
12 |
string SongTime = dir.GetDetailsOf(item, 27); //27为获得歌曲持续时间 ,28为获得音乐速率,1为获得音乐文件大小 |
13 |
string [] time = Regex.Split(SongTime, ":" ); |
14 |
return time; |
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, string arg) |
07 |
{ |
08 |
using (var p = new Process()) |
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( object sender, 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 |
int bitrate = Convert.ToInt32(cobBitRate.Text) * 1000; //恒定码率 |
09 |
string Hz = 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 in listMusics.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( object sender, EventArgs e) |
02 |
{ |
03 |
SaveFileDialog saveMusic = new SaveFileDialog(); |
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 |
string startTime = string .Format( "0:{0}:{1}" , txtBeginM.Text, txtBeginS.Text).Trim(); //歌曲起始时间 |
09 |
int duration = (Convert.ToInt32( this .txtEndM.Text) * 60 + Convert.ToInt32( this .txtEndS.Text)) - (Convert.ToInt32( this .txtBeginM.Text) * 60 + Convert.ToInt32( this .txtBeginS.Text)); |
10 |
string endTime = string .Format( "0:{0}:{1}" , duration / 60, duration % 60); //endTime是持续的时间,不是歌曲结束的时间 |
11 |
if (saveMusic.ShowDialog() == DialogResult.OK) |
12 |
{ |
13 |
string savePath = 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的应用。