diff --git a/CUEPlayer/CUEPlayer.csproj b/CUEPlayer/CUEPlayer.csproj index d16a30b..9e63f88 100644 --- a/CUEPlayer/CUEPlayer.csproj +++ b/CUEPlayer/CUEPlayer.csproj @@ -84,6 +84,18 @@ frmCUEPlayer.cs + + Form + + + Icecast.cs + + + Form + + + IcecastSettings.cs + Form @@ -107,6 +119,12 @@ frmCUEPlayer.cs + + Icecast.cs + + + IcecastSettings.cs + Output.cs @@ -132,6 +150,7 @@ Settings.settings True + @@ -146,6 +165,10 @@ {FAD09EE2-D6B2-4A8E-9F1C-2A9FB293661A} CUETools.Codecs.CoreAudio + + {8FC5DA7C-F6AC-4D04-85BC-1233DDF569E7} + CUETools.Codecs.Icecast + {6458A13A-30EF-45A9-9D58-E5031B17BEE2} CUETools.Codecs @@ -248,6 +271,13 @@ + + + + + + + diff --git a/CUEPlayer/CUEPlayer.sdf b/CUEPlayer/CUEPlayer.sdf index 7626ba6..e33b1cf 100644 Binary files a/CUEPlayer/CUEPlayer.sdf and b/CUEPlayer/CUEPlayer.sdf differ diff --git a/CUEPlayer/DataSet1.Designer.cs b/CUEPlayer/DataSet1.Designer.cs index c9f6c9e..b23b8b6 100644 --- a/CUEPlayer/DataSet1.Designer.cs +++ b/CUEPlayer/DataSet1.Designer.cs @@ -458,10 +458,10 @@ namespace CUEPlayer { this.columnid.ReadOnly = true; this.columnid.Unique = true; this.columnpath.AllowDBNull = false; - this.columnpath.MaxLength = 100; - this.columnartist.MaxLength = 100; - this.columntitle.MaxLength = 100; - this.columnalbum.MaxLength = 100; + this.columnpath.MaxLength = 255; + this.columnartist.MaxLength = 255; + this.columntitle.MaxLength = 255; + this.columnalbum.MaxLength = 255; } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] @@ -616,11 +616,11 @@ namespace CUEPlayer { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public string artist { get { - try { - return ((string)(this[this.tablePlaylist.artistColumn])); + if (this.IsartistNull()) { + return string.Empty; } - catch (global::System.InvalidCastException e) { - throw new global::System.Data.StrongTypingException("The value for column \'artist\' in table \'Playlist\' is DBNull.", e); + else { + return ((string)(this[this.tablePlaylist.artistColumn])); } } set { @@ -631,11 +631,11 @@ namespace CUEPlayer { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public string title { get { - try { - return ((string)(this[this.tablePlaylist.titleColumn])); + if (this.IstitleNull()) { + return string.Empty; } - catch (global::System.InvalidCastException e) { - throw new global::System.Data.StrongTypingException("The value for column \'title\' in table \'Playlist\' is DBNull.", e); + else { + return ((string)(this[this.tablePlaylist.titleColumn])); } } set { @@ -646,11 +646,11 @@ namespace CUEPlayer { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public string album { get { - try { - return ((string)(this[this.tablePlaylist.albumColumn])); + if (this.IsalbumNull()) { + return string.Empty; } - catch (global::System.InvalidCastException e) { - throw new global::System.Data.StrongTypingException("The value for column \'album\' in table \'Playlist\' is DBNull.", e); + else { + return ((string)(this[this.tablePlaylist.albumColumn])); } } set { diff --git a/CUEPlayer/DataSet1.xsd b/CUEPlayer/DataSet1.xsd index ec8a857..987caa8 100644 --- a/CUEPlayer/DataSet1.xsd +++ b/CUEPlayer/DataSet1.xsd @@ -32,7 +32,7 @@ - + SELECT [id], [path], [artist], [title], [album], [length], [track] FROM [Playlist] @@ -69,43 +69,43 @@ - + - + - - + + - + - + - + - + - + - + - + - - + + diff --git a/CUEPlayer/DataSet1.xss b/CUEPlayer/DataSet1.xss index 5f28270..c50a493 100644 --- a/CUEPlayer/DataSet1.xss +++ b/CUEPlayer/DataSet1.xss @@ -1 +1,12 @@ - \ No newline at end of file + + + + + + + + \ No newline at end of file diff --git a/CUEPlayer/Deck.Designer.cs b/CUEPlayer/Deck.Designer.cs index ca284d4..7a152c3 100644 --- a/CUEPlayer/Deck.Designer.cs +++ b/CUEPlayer/Deck.Designer.cs @@ -134,7 +134,7 @@ this.mediaSlider.ButtonStyle = MediaSlider.MediaSlider.ButtonType.GlassOverlap; this.mediaSlider.ContextMenuStrip = null; this.mediaSlider.LargeChange = 2; - this.mediaSlider.Location = new System.Drawing.Point(0, 115); + this.mediaSlider.Location = new System.Drawing.Point(0, 112); this.mediaSlider.Margin = new System.Windows.Forms.Padding(0); this.mediaSlider.Maximum = 1; this.mediaSlider.Minimum = 0; @@ -242,7 +242,7 @@ this.AllowDrop = true; this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(361, 145); + this.ClientSize = new System.Drawing.Size(361, 136); this.ControlBox = false; this.Controls.Add(this.buttonNext); this.Controls.Add(this.buttonRewind); @@ -262,6 +262,7 @@ this.Name = "Deck"; this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; this.Text = "Deck"; + this.Load += new System.EventHandler(this.Deck_Load); this.DragDrop += new System.Windows.Forms.DragEventHandler(this.Deck_DragDrop); this.DragOver += new System.Windows.Forms.DragEventHandler(this.Deck_DragOver); ((System.ComponentModel.ISupportInitialize)(this.pictureBox)).EndInit(); diff --git a/CUEPlayer/Deck.cs b/CUEPlayer/Deck.cs index d654ab3..d21f0f1 100644 --- a/CUEPlayer/Deck.cs +++ b/CUEPlayer/Deck.cs @@ -21,6 +21,7 @@ namespace CUEPlayer long playingFinish = 0; Thread playThread; int iSource; + AudioBuffer buff; MixingSource mixer; MixingWriter writer; Deck nextDeck; @@ -72,12 +73,15 @@ namespace CUEPlayer textBoxAlbum.Text = playingRow < 0 ? "" : dataSet.Playlist[playingRow].album; textBoxTitle.Text = playingRow < 0 ? "" : dataSet.Playlist[playingRow].title; textBoxDuration.Text = ""; - pictureBox.Image = playingCue != null ? playingCue.Cover : pictureBox.InitialImage; + pictureBox.Image = playingCue != null && playingCue.Cover != null ? playingCue.Cover : pictureBox.InitialImage; if (nextDeck != null && nextDeck.playingSource == null && playingRow >= 0 && playingRow < dataSet.Playlist.Rows.Count - 1) { nextDeck.LoadDeck(playingRow + 1); } + + if (playThread != null) + (MdiParent as frmCUEPlayer).UpdateMetadata(textBoxArtist.Text, textBoxTitle.Text); } mediaSlider.Enabled = playingSource != null; if (playingSource != null) @@ -101,8 +105,6 @@ namespace CUEPlayer private void PlayThread() { - AudioBuffer buff = new AudioBuffer(playingSource.PCM, 0x2000); - try { do @@ -151,6 +153,8 @@ namespace CUEPlayer nextDeck.playingRow = -1; nextDeck.needUpdate = true; } + if (buff == null || buff.PCM.SampleRate != playingSource.PCM.SampleRate || buff.PCM.ChannelCount != playingSource.PCM.ChannelCount || buff.PCM.BitsPerSample != playingSource.PCM.BitsPerSample) + buff = new AudioBuffer(playingSource.PCM, 0x2000); playingSource.Read(buff, Math.Min(buff.Size, (int)(playingFinish - playingSource.Position))); writer.Write(buff); } @@ -205,12 +209,6 @@ namespace CUEPlayer private void buttonPlay_Click(object sender, EventArgs e) { - if (playingSource == null) - { - Playlist playlist = (MdiParent as frmCUEPlayer).wndPlaylist; - LoadDeck(playlist.List.SelectedIndices[0]); - } - mixer.BufferPlaying(iSource, true); if (playThread == null) { playThread = new Thread(PlayThread); @@ -219,6 +217,12 @@ namespace CUEPlayer playThread.Name = Text; playThread.Start(); } + if (playingSource == null) + { + Playlist playlist = (MdiParent as frmCUEPlayer).wndPlaylist; + LoadDeck(playlist.List.SelectedIndices[0]); + } + mixer.BufferPlaying(iSource, true); } private void buttonStop_Click(object sender, EventArgs e) @@ -313,5 +317,10 @@ namespace CUEPlayer playingSource.Position = playingStart; } } + + private void Deck_Load(object sender, EventArgs e) + { + + } } } diff --git a/CUEPlayer/Icecast.Designer.cs b/CUEPlayer/Icecast.Designer.cs new file mode 100644 index 0000000..b512ed0 --- /dev/null +++ b/CUEPlayer/Icecast.Designer.cs @@ -0,0 +1,119 @@ +namespace CUEPlayer +{ + partial class Icecast + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.timer1 = new System.Windows.Forms.Timer(this.components); + this.textBoxBytes = new System.Windows.Forms.TextBox(); + this.checkBoxTransmit = new System.Windows.Forms.CheckBox(); + this.buttonSettings = new System.Windows.Forms.Button(); + this.textBoxLatency = new System.Windows.Forms.TextBox(); + this.toolTip1 = new System.Windows.Forms.ToolTip(this.components); + this.SuspendLayout(); + // + // timer1 + // + this.timer1.Enabled = true; + this.timer1.Tick += new System.EventHandler(this.timer1_Tick); + // + // textBoxBytes + // + this.textBoxBytes.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.textBoxBytes.Enabled = false; + this.textBoxBytes.Location = new System.Drawing.Point(2, 87); + this.textBoxBytes.Name = "textBoxBytes"; + this.textBoxBytes.ReadOnly = true; + this.textBoxBytes.Size = new System.Drawing.Size(70, 13); + this.textBoxBytes.TabIndex = 14; + this.textBoxBytes.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; + // + // checkBoxTransmit + // + this.checkBoxTransmit.Appearance = System.Windows.Forms.Appearance.Button; + this.checkBoxTransmit.AutoSize = true; + this.checkBoxTransmit.Image = global::CUEPlayer.Properties.Resources.transmit_blue; + this.checkBoxTransmit.Location = new System.Drawing.Point(14, 106); + this.checkBoxTransmit.Name = "checkBoxTransmit"; + this.checkBoxTransmit.Size = new System.Drawing.Size(22, 22); + this.checkBoxTransmit.TabIndex = 15; + this.checkBoxTransmit.UseVisualStyleBackColor = true; + this.checkBoxTransmit.CheckedChanged += new System.EventHandler(this.checkBoxTransmit_CheckedChanged); + // + // buttonSettings + // + this.buttonSettings.AutoSize = true; + this.buttonSettings.Image = global::CUEPlayer.Properties.Resources.cog; + this.buttonSettings.Location = new System.Drawing.Point(42, 106); + this.buttonSettings.Name = "buttonSettings"; + this.buttonSettings.Size = new System.Drawing.Size(22, 22); + this.buttonSettings.TabIndex = 16; + this.buttonSettings.UseVisualStyleBackColor = true; + this.buttonSettings.Click += new System.EventHandler(this.buttonSettings_Click); + // + // textBoxLatency + // + this.textBoxLatency.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.textBoxLatency.Enabled = false; + this.textBoxLatency.Location = new System.Drawing.Point(2, 62); + this.textBoxLatency.Name = "textBoxLatency"; + this.textBoxLatency.ReadOnly = true; + this.textBoxLatency.Size = new System.Drawing.Size(70, 13); + this.textBoxLatency.TabIndex = 17; + this.textBoxLatency.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; + // + // Icecast + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(74, 136); + this.Controls.Add(this.textBoxLatency); + this.Controls.Add(this.buttonSettings); + this.Controls.Add(this.checkBoxTransmit); + this.Controls.Add(this.textBoxBytes); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "Icecast"; + this.Text = "Icecast"; + this.Load += new System.EventHandler(this.Icecast_Load); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Timer timer1; + private System.Windows.Forms.TextBox textBoxBytes; + private System.Windows.Forms.CheckBox checkBoxTransmit; + private System.Windows.Forms.Button buttonSettings; + private System.Windows.Forms.TextBox textBoxLatency; + private System.Windows.Forms.ToolTip toolTip1; + } +} \ No newline at end of file diff --git a/CUEPlayer/Icecast.cs b/CUEPlayer/Icecast.cs new file mode 100644 index 0000000..b0cf3f5 --- /dev/null +++ b/CUEPlayer/Icecast.cs @@ -0,0 +1,142 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Text; +using System.Windows.Forms; +using System.Diagnostics; +using System.Threading; +using System.Net; +using CUETools.Codecs; +using CUETools.Codecs.Icecast; + +namespace CUEPlayer +{ + public partial class Icecast : Form + { + private IcecastWriter _icecastWriter; + private IcecastSettingsData _icecastSettings; + private CUETools.DSP.Mixer.MixingSource _mixer; + private Thread flushThread; + private AudioPipe buffer; + private bool close = false; + private int latency = 0; + + public Icecast() + { + InitializeComponent(); + } + + private void Icecast_Load(object sender, EventArgs e) + { + if (Properties.Settings.Default.IcecastSettings == null) + Properties.Settings.Default.IcecastSettings = new IcecastSettingsData(); + _icecastSettings = Properties.Settings.Default.IcecastSettings; + } + + public void Init(frmCUEPlayer parent) + { + MdiParent = parent; + Show(); + _mixer = parent.Mixer; + buffer = new AudioPipe(_mixer.PCM, _mixer.PCM.SampleRate * 10); // 10 secs + _mixer.AudioRead += new EventHandler(Mixer_AudioRead); + parent.updateMetadata += new EventHandler(parent_updateMetadata); + + flushThread = new Thread(FlushThread); + flushThread.Priority = ThreadPriority.AboveNormal; + flushThread.IsBackground = true; + flushThread.Name = "Icecast"; + flushThread.Start(); + } + + void parent_updateMetadata(object sender, UpdateMetadataEvent e) + { + if (_icecastWriter != null) + _icecastWriter.UpdateMetadata(e.artist, e.title); + } + + private void FlushThread() + { + AudioBuffer result = new AudioBuffer(_mixer.PCM, _mixer.BufferSize); + while (true) + { + buffer.Read(result, -1); + if (_icecastWriter != null && !close) + { + try + { + _icecastWriter.Write(result); + } + catch (Exception ex) + { + close = true; + } + } + if (_icecastWriter != null && close) + { + _icecastWriter.Delete(); + _icecastWriter = null; + } + } + } + + void Mixer_AudioRead(object sender, CUETools.DSP.Mixer.AudioReadEventArgs e) + { + latency = buffer.Write(e.buffer); + //int bs = buffer.Write(e.buffer); + //if (bs > 0) + //{ + // Trace.WriteLine(string.Format("buffer size {0}", bs)); + //} + } + + private void timer1_Tick(object sender, EventArgs e) + { + textBoxBytes.Text = _icecastWriter == null ? "" : string.Format("{0}K", _icecastWriter.BytesWritten/1024); + textBoxLatency.Text = (_icecastWriter == null || latency == 0 ) ? "" : string.Format("{0}", 1.0 * latency / buffer.PCM.SampleRate); + } + + private void checkBoxTransmit_CheckedChanged(object sender, EventArgs e) + { + close = !checkBoxTransmit.Checked; + this.toolTip1.SetToolTip(this.checkBoxTransmit, ""); + if (!close && _icecastWriter == null) + { + IcecastWriter icecastWriter = new IcecastWriter(_mixer.PCM, _icecastSettings); + try + { + icecastWriter.Connect(); + if (icecastWriter.Response.StatusCode == HttpStatusCode.OK) + _icecastWriter = icecastWriter; + else + { + toolTip1.ToolTipIcon = ToolTipIcon.Error; + toolTip1.ToolTipTitle = icecastWriter.Response.StatusCode.ToString(); + toolTip1.IsBalloon = true; + //toolTip1.Show(resp.StatusDescription, checkBoxTransmit, 0, 0, 2000); + toolTip1.SetToolTip(checkBoxTransmit, icecastWriter.Response.StatusDescription); + } + } + catch (Exception ex) + { + Trace.WriteLine(ex.Message); + icecastWriter.Close(); + toolTip1.ToolTipIcon = ToolTipIcon.Error; + toolTip1.ToolTipTitle = "Exception"; + toolTip1.IsBalloon = true; + //toolTip1.Show(ex.Message, checkBoxTransmit, 0, 0, 2000); + toolTip1.SetToolTip(checkBoxTransmit, ex.Message); + } + } + } + + private void buttonSettings_Click(object sender, EventArgs e) + { + IcecastSettings frm = new IcecastSettings(_icecastSettings); + if (frm.ShowDialog(this) == DialogResult.OK) + Properties.Settings.Default.Save(); + } + } +} diff --git a/CUEPlayer/Icecast.resx b/CUEPlayer/Icecast.resx new file mode 100644 index 0000000..7a6b65e --- /dev/null +++ b/CUEPlayer/Icecast.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 104, 17 + + \ No newline at end of file diff --git a/CUEPlayer/IcecastSettings.Designer.cs b/CUEPlayer/IcecastSettings.Designer.cs new file mode 100644 index 0000000..bd3f528 --- /dev/null +++ b/CUEPlayer/IcecastSettings.Designer.cs @@ -0,0 +1,301 @@ +namespace CUEPlayer +{ + partial class IcecastSettings + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(IcecastSettings)); + this.buttonCancel = new System.Windows.Forms.Button(); + this.buttonOk = new System.Windows.Forms.Button(); + this.textBoxServer = new System.Windows.Forms.TextBox(); + this.textBoxPort = new System.Windows.Forms.TextBox(); + this.textBoxPassword = new System.Windows.Forms.TextBox(); + this.textBoxMount = new System.Windows.Forms.TextBox(); + this.textBoxName = new System.Windows.Forms.TextBox(); + this.textBoxDesctiption = new System.Windows.Forms.TextBox(); + this.textBoxWeb = new System.Windows.Forms.TextBox(); + this.comboBoxGenre = new System.Windows.Forms.ComboBox(); + this.labelServer = new System.Windows.Forms.Label(); + this.labelPort = new System.Windows.Forms.Label(); + this.labelPassword = new System.Windows.Forms.Label(); + this.labelMount = new System.Windows.Forms.Label(); + this.labelStationName = new System.Windows.Forms.Label(); + this.labelStationDescription = new System.Windows.Forms.Label(); + this.labelWeb = new System.Windows.Forms.Label(); + this.labelGenre = new System.Windows.Forms.Label(); + this.textBoxMP3Options = new System.Windows.Forms.TextBox(); + this.labelMP3Options = new System.Windows.Forms.Label(); + this.icecastSettingsDataBindingSource = new System.Windows.Forms.BindingSource(this.components); + ((System.ComponentModel.ISupportInitialize)(this.icecastSettingsDataBindingSource)).BeginInit(); + this.SuspendLayout(); + // + // buttonCancel + // + this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.buttonCancel.Location = new System.Drawing.Point(197, 272); + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.Size = new System.Drawing.Size(75, 23); + this.buttonCancel.TabIndex = 0; + this.buttonCancel.Text = "Cancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + // + // buttonOk + // + this.buttonOk.DialogResult = System.Windows.Forms.DialogResult.OK; + this.buttonOk.Location = new System.Drawing.Point(116, 272); + this.buttonOk.Name = "buttonOk"; + this.buttonOk.Size = new System.Drawing.Size(75, 23); + this.buttonOk.TabIndex = 1; + this.buttonOk.Text = "OK"; + this.buttonOk.UseVisualStyleBackColor = true; + // + // textBoxServer + // + this.textBoxServer.DataBindings.Add(new System.Windows.Forms.Binding("Text", this.icecastSettingsDataBindingSource, "Server", true)); + this.textBoxServer.Location = new System.Drawing.Point(91, 12); + this.textBoxServer.Name = "textBoxServer"; + this.textBoxServer.Size = new System.Drawing.Size(181, 20); + this.textBoxServer.TabIndex = 2; + // + // textBoxPort + // + this.textBoxPort.DataBindings.Add(new System.Windows.Forms.Binding("Text", this.icecastSettingsDataBindingSource, "Port", true)); + this.textBoxPort.Location = new System.Drawing.Point(91, 38); + this.textBoxPort.Name = "textBoxPort"; + this.textBoxPort.Size = new System.Drawing.Size(181, 20); + this.textBoxPort.TabIndex = 3; + // + // textBoxPassword + // + this.textBoxPassword.DataBindings.Add(new System.Windows.Forms.Binding("Text", this.icecastSettingsDataBindingSource, "Password", true)); + this.textBoxPassword.Location = new System.Drawing.Point(91, 64); + this.textBoxPassword.Name = "textBoxPassword"; + this.textBoxPassword.Size = new System.Drawing.Size(181, 20); + this.textBoxPassword.TabIndex = 4; + this.textBoxPassword.UseSystemPasswordChar = true; + // + // textBoxMount + // + this.textBoxMount.DataBindings.Add(new System.Windows.Forms.Binding("Text", this.icecastSettingsDataBindingSource, "Mount", true)); + this.textBoxMount.Location = new System.Drawing.Point(91, 90); + this.textBoxMount.Name = "textBoxMount"; + this.textBoxMount.Size = new System.Drawing.Size(181, 20); + this.textBoxMount.TabIndex = 5; + // + // textBoxName + // + this.textBoxName.DataBindings.Add(new System.Windows.Forms.Binding("Text", this.icecastSettingsDataBindingSource, "Name", true)); + this.textBoxName.Location = new System.Drawing.Point(91, 116); + this.textBoxName.Name = "textBoxName"; + this.textBoxName.Size = new System.Drawing.Size(181, 20); + this.textBoxName.TabIndex = 6; + // + // textBoxDesctiption + // + this.textBoxDesctiption.DataBindings.Add(new System.Windows.Forms.Binding("Text", this.icecastSettingsDataBindingSource, "Desctiption", true)); + this.textBoxDesctiption.Location = new System.Drawing.Point(91, 142); + this.textBoxDesctiption.Name = "textBoxDesctiption"; + this.textBoxDesctiption.Size = new System.Drawing.Size(181, 20); + this.textBoxDesctiption.TabIndex = 7; + // + // textBoxWeb + // + this.textBoxWeb.DataBindings.Add(new System.Windows.Forms.Binding("Text", this.icecastSettingsDataBindingSource, "Url", true)); + this.textBoxWeb.Location = new System.Drawing.Point(91, 168); + this.textBoxWeb.Name = "textBoxWeb"; + this.textBoxWeb.Size = new System.Drawing.Size(181, 20); + this.textBoxWeb.TabIndex = 8; + // + // comboBoxGenre + // + this.comboBoxGenre.DataBindings.Add(new System.Windows.Forms.Binding("Text", this.icecastSettingsDataBindingSource, "Genre", true)); + this.comboBoxGenre.FormattingEnabled = true; + this.comboBoxGenre.Location = new System.Drawing.Point(91, 194); + this.comboBoxGenre.Name = "comboBoxGenre"; + this.comboBoxGenre.Size = new System.Drawing.Size(181, 21); + this.comboBoxGenre.TabIndex = 9; + // + // labelServer + // + this.labelServer.AutoSize = true; + this.labelServer.Location = new System.Drawing.Point(12, 15); + this.labelServer.Name = "labelServer"; + this.labelServer.Size = new System.Drawing.Size(38, 13); + this.labelServer.TabIndex = 10; + this.labelServer.Text = "Server"; + // + // labelPort + // + this.labelPort.AutoSize = true; + this.labelPort.Location = new System.Drawing.Point(12, 41); + this.labelPort.Name = "labelPort"; + this.labelPort.Size = new System.Drawing.Size(26, 13); + this.labelPort.TabIndex = 11; + this.labelPort.Text = "Port"; + // + // labelPassword + // + this.labelPassword.AutoSize = true; + this.labelPassword.Location = new System.Drawing.Point(12, 67); + this.labelPassword.Name = "labelPassword"; + this.labelPassword.Size = new System.Drawing.Size(53, 13); + this.labelPassword.TabIndex = 12; + this.labelPassword.Text = "Password"; + // + // labelMount + // + this.labelMount.AutoSize = true; + this.labelMount.Location = new System.Drawing.Point(12, 93); + this.labelMount.Name = "labelMount"; + this.labelMount.Size = new System.Drawing.Size(37, 13); + this.labelMount.TabIndex = 13; + this.labelMount.Text = "Mount"; + // + // labelStationName + // + this.labelStationName.AutoSize = true; + this.labelStationName.Location = new System.Drawing.Point(12, 119); + this.labelStationName.Name = "labelStationName"; + this.labelStationName.Size = new System.Drawing.Size(35, 13); + this.labelStationName.TabIndex = 14; + this.labelStationName.Text = "Name"; + // + // labelStationDescription + // + this.labelStationDescription.AutoSize = true; + this.labelStationDescription.Location = new System.Drawing.Point(12, 145); + this.labelStationDescription.Name = "labelStationDescription"; + this.labelStationDescription.Size = new System.Drawing.Size(60, 13); + this.labelStationDescription.TabIndex = 15; + this.labelStationDescription.Text = "Description"; + // + // labelWeb + // + this.labelWeb.AutoSize = true; + this.labelWeb.Location = new System.Drawing.Point(12, 171); + this.labelWeb.Name = "labelWeb"; + this.labelWeb.Size = new System.Drawing.Size(30, 13); + this.labelWeb.TabIndex = 16; + this.labelWeb.Text = "Web"; + // + // labelGenre + // + this.labelGenre.AutoSize = true; + this.labelGenre.Location = new System.Drawing.Point(12, 197); + this.labelGenre.Name = "labelGenre"; + this.labelGenre.Size = new System.Drawing.Size(36, 13); + this.labelGenre.TabIndex = 17; + this.labelGenre.Text = "Genre"; + // + // textBoxMP3Options + // + this.textBoxMP3Options.DataBindings.Add(new System.Windows.Forms.Binding("Text", this.icecastSettingsDataBindingSource, "MP3Options", true)); + this.textBoxMP3Options.Location = new System.Drawing.Point(91, 221); + this.textBoxMP3Options.Name = "textBoxMP3Options"; + this.textBoxMP3Options.Size = new System.Drawing.Size(181, 20); + this.textBoxMP3Options.TabIndex = 18; + // + // labelMP3Options + // + this.labelMP3Options.AutoSize = true; + this.labelMP3Options.Location = new System.Drawing.Point(12, 224); + this.labelMP3Options.Name = "labelMP3Options"; + this.labelMP3Options.Size = new System.Drawing.Size(68, 13); + this.labelMP3Options.TabIndex = 19; + this.labelMP3Options.Text = "MP3 Options"; + // + // icecastSettingsDataBindingSource + // + this.icecastSettingsDataBindingSource.DataSource = typeof(CUETools.Codecs.Icecast.IcecastSettingsData); + // + // IcecastSettings + // + this.AcceptButton = this.buttonOk; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.buttonCancel; + this.ClientSize = new System.Drawing.Size(284, 307); + this.Controls.Add(this.labelMP3Options); + this.Controls.Add(this.textBoxMP3Options); + this.Controls.Add(this.labelGenre); + this.Controls.Add(this.labelWeb); + this.Controls.Add(this.labelStationDescription); + this.Controls.Add(this.labelStationName); + this.Controls.Add(this.labelMount); + this.Controls.Add(this.labelPassword); + this.Controls.Add(this.labelPort); + this.Controls.Add(this.labelServer); + this.Controls.Add(this.comboBoxGenre); + this.Controls.Add(this.textBoxWeb); + this.Controls.Add(this.textBoxDesctiption); + this.Controls.Add(this.textBoxName); + this.Controls.Add(this.textBoxMount); + this.Controls.Add(this.textBoxPassword); + this.Controls.Add(this.textBoxPort); + this.Controls.Add(this.textBoxServer); + this.Controls.Add(this.buttonOk); + this.Controls.Add(this.buttonCancel); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "IcecastSettings"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Icecast Settings"; + this.Load += new System.EventHandler(this.IcecastSettings_Load); + ((System.ComponentModel.ISupportInitialize)(this.icecastSettingsDataBindingSource)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button buttonCancel; + private System.Windows.Forms.Button buttonOk; + private System.Windows.Forms.TextBox textBoxServer; + private System.Windows.Forms.TextBox textBoxPort; + private System.Windows.Forms.TextBox textBoxPassword; + private System.Windows.Forms.TextBox textBoxMount; + private System.Windows.Forms.TextBox textBoxName; + private System.Windows.Forms.TextBox textBoxDesctiption; + private System.Windows.Forms.TextBox textBoxWeb; + private System.Windows.Forms.ComboBox comboBoxGenre; + private System.Windows.Forms.Label labelServer; + private System.Windows.Forms.Label labelPort; + private System.Windows.Forms.Label labelPassword; + private System.Windows.Forms.Label labelMount; + private System.Windows.Forms.Label labelStationName; + private System.Windows.Forms.Label labelStationDescription; + private System.Windows.Forms.Label labelWeb; + private System.Windows.Forms.Label labelGenre; + private System.Windows.Forms.BindingSource icecastSettingsDataBindingSource; + private System.Windows.Forms.TextBox textBoxMP3Options; + private System.Windows.Forms.Label labelMP3Options; + } +} \ No newline at end of file diff --git a/CUEPlayer/IcecastSettings.cs b/CUEPlayer/IcecastSettings.cs new file mode 100644 index 0000000..ee14f5a --- /dev/null +++ b/CUEPlayer/IcecastSettings.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Text; +using System.Windows.Forms; +using CUETools.Codecs.Icecast; + +namespace CUEPlayer +{ + public partial class IcecastSettings : Form + { + public IcecastSettings(IcecastSettingsData data) + { + InitializeComponent(); + icecastSettingsDataBindingSource.DataSource = data; + } + + private void IcecastSettings_Load(object sender, EventArgs e) + { + + } + } +} diff --git a/CUEPlayer/IcecastSettings.resx b/CUEPlayer/IcecastSettings.resx new file mode 100644 index 0000000..b42b501 --- /dev/null +++ b/CUEPlayer/IcecastSettings.resx @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + + + AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAQAQAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACjo6OampqaTgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF9fX01aWlpKWlpaAwAA + AAAAAAAAAAAAAAAAAAAAAAAAra2tS6Ojo+Sampp8AAAAAAAAAAAAAAAAAAAAAGxsbIBlZWXAX19fRQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACtra28o6Oj95qampwAAAAAAAAAAH19faN0dHTzbGxsrgAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtra2MK2trf2jo6P+mpqaxJCQkMSGhob+fX199HR0 + dCQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC2traWra2t/Ofk4//l4uH/kJCQ/IaG + hocAAAAAAAAAAAAAAAAAAAAAAAAAAOCfam/emmZm3ZdfDwAAAAAAAAAAv7+/Era2tvOtra3+o6Oj/pqa + muWQkJAMAAAAAAAAAAAAAAAA1Xs4P9V7OFXipXXb5K6E/96davbdmWMG3ZZcPgAAAAC/v7+j2tnY/9vZ + 2P+jo6OiAAAAANV+PCzVfTkF1Xs45NmGSf/VezjV5auA+e3Fp//ipHX/4J9tCd+daP/dl2Pq0q2PPL+/ + v/u2trb6vZ+ISNiGR+HXhEP/1YI9CdV/PP/jp3r/1Xs48+ayifnuyq3/5ap+/+OneAPionL246d3/96a + Zj/Hx8dOv7+/KtuPUz/dlV3/2IlK9teFRAPVgkD/46p9/9V9OfDotpHY7suu/+Wxif/lrYIJ46h7q+e1 + jv/goXCq3p1qP92ZYz/dllyq4qV2/9qOU6vaiU0J2YlI/+Knev/Vgj/V6byZkOzHqf/qvZv/5rOLQuWu + hRvlq4De6LWP/+Srf//jp3r/5KyA/92XY97dlFsb25FWQt2XX//goG7/2IZHjevBny3rvpz87syw/+i4 + lPzmto4f5rKJDOWug4Tlqn7G46d4xuKicoTgn2oM3ppmH92XX/zlrID/249T/NqLTioAAAAA7MOikO7J + rv/vyq3/6buX/Oi2kULmtYwJAAAAAAAAAADjqHsJ4qV1QuChcPzlsIb/4qh6/92WXI0AAAAAAAAAAOzE + pQbsxKS37squ//DNtP/rwqL/6LqV/+i2kf/ms4v/5a+G/+ezi//qu5n/5rGI/+CfbbfenGcGAAAAAAAA + AAAAAAAAAAAAAOzEpXLsw6L2782x//HQuP/x07v/8NC5/+3Lrv/rwKD/5a6D9uWqfnIAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA7MSlJ+zEpY3sw6LM67+f/Ou+mvzpu5fM6LaRjea1jCcAAAAAAAAAAAAA + AAAAAAAA5+MAAOPHAADxjwAA8A8AAPgfAAAYHAAABCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgYEAAIAB + AADgBwAA8A8AAA== + + + \ No newline at end of file diff --git a/CUEPlayer/Output.Designer.cs b/CUEPlayer/Output.Designer.cs index 6d82c7a..d1d7863 100644 --- a/CUEPlayer/Output.Designer.cs +++ b/CUEPlayer/Output.Designer.cs @@ -29,12 +29,14 @@ private void InitializeComponent() { this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Output)); this.mediaSliderVolume = new MediaSlider.MediaSlider(); this.peakMeterCtrl1 = new Ernzo.WinForms.Controls.PeakMeterCtrl(); - this.buttonPause = new System.Windows.Forms.Button(); - this.buttonPlay = new System.Windows.Forms.Button(); - this.buttonStop = new System.Windows.Forms.Button(); this.timer1 = new System.Windows.Forms.Timer(this.components); + this.checkBoxMute = new System.Windows.Forms.CheckBox(); + this.imageList1 = new System.Windows.Forms.ImageList(this.components); + this.outputBindingSource = new System.Windows.Forms.BindingSource(this.components); + ((System.ComponentModel.ISupportInitialize)(this.outputBindingSource)).BeginInit(); this.SuspendLayout(); // // mediaSliderVolume @@ -61,7 +63,7 @@ this.mediaSliderVolume.Name = "mediaSliderVolume"; this.mediaSliderVolume.Orientation = System.Windows.Forms.Orientation.Vertical; this.mediaSliderVolume.ShowButtonOnHover = false; - this.mediaSliderVolume.Size = new System.Drawing.Size(37, 114); + this.mediaSliderVolume.Size = new System.Drawing.Size(37, 101); this.mediaSliderVolume.SliderFlyOut = MediaSlider.MediaSlider.FlyOutStyle.None; this.mediaSliderVolume.SmallChange = 1; this.mediaSliderVolume.SmoothScrolling = true; @@ -91,63 +93,61 @@ this.peakMeterCtrl1.FalloffColor = System.Drawing.Color.Blue; this.peakMeterCtrl1.GridColor = System.Drawing.Color.Gainsboro; this.peakMeterCtrl1.LEDCount = 25; - this.peakMeterCtrl1.Location = new System.Drawing.Point(60, 9); + this.peakMeterCtrl1.Location = new System.Drawing.Point(46, 9); this.peakMeterCtrl1.Margin = new System.Windows.Forms.Padding(0); this.peakMeterCtrl1.Name = "peakMeterCtrl1"; - this.peakMeterCtrl1.Size = new System.Drawing.Size(15, 109); + this.peakMeterCtrl1.Size = new System.Drawing.Size(15, 101); this.peakMeterCtrl1.TabIndex = 13; this.peakMeterCtrl1.Text = "peakMeterCtrl1"; // - // buttonPause - // - this.buttonPause.Image = global::CUEPlayer.Properties.Resources.control_pause_blue; - this.buttonPause.Location = new System.Drawing.Point(59, 130); - this.buttonPause.Name = "buttonPause"; - this.buttonPause.Size = new System.Drawing.Size(25, 25); - this.buttonPause.TabIndex = 12; - this.buttonPause.UseVisualStyleBackColor = true; - this.buttonPause.Click += new System.EventHandler(this.buttonPause_Click); - // - // buttonPlay - // - this.buttonPlay.BackColor = System.Drawing.Color.Transparent; - this.buttonPlay.BackgroundImage = global::CUEPlayer.Properties.Resources.control_play_blue; - this.buttonPlay.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center; - this.buttonPlay.FlatAppearance.BorderSize = 0; - this.buttonPlay.Location = new System.Drawing.Point(9, 130); - this.buttonPlay.Name = "buttonPlay"; - this.buttonPlay.Size = new System.Drawing.Size(25, 25); - this.buttonPlay.TabIndex = 10; - this.buttonPlay.UseVisualStyleBackColor = false; - this.buttonPlay.Click += new System.EventHandler(this.buttonPlay_Click); - // - // buttonStop - // - this.buttonStop.Image = global::CUEPlayer.Properties.Resources.control_stop_blue; - this.buttonStop.Location = new System.Drawing.Point(34, 130); - this.buttonStop.Name = "buttonStop"; - this.buttonStop.Size = new System.Drawing.Size(25, 25); - this.buttonStop.TabIndex = 11; - this.buttonStop.UseVisualStyleBackColor = true; - this.buttonStop.Click += new System.EventHandler(this.buttonStop_Click); - // // timer1 // this.timer1.Enabled = true; this.timer1.Interval = 50; this.timer1.Tick += new System.EventHandler(this.timer1_Tick); // + // checkBoxMute + // + this.checkBoxMute.Appearance = System.Windows.Forms.Appearance.Button; + this.checkBoxMute.Checked = true; + this.checkBoxMute.CheckState = System.Windows.Forms.CheckState.Checked; + this.checkBoxMute.DataBindings.Add(new System.Windows.Forms.Binding("Checked", this.outputBindingSource, "Muted", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged)); + this.checkBoxMute.DataBindings.Add(new System.Windows.Forms.Binding("ImageIndex", this.outputBindingSource, "VolumeIcon", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged)); + this.checkBoxMute.FlatAppearance.BorderSize = 0; + this.checkBoxMute.FlatAppearance.CheckedBackColor = System.Drawing.Color.Transparent; + this.checkBoxMute.FlatAppearance.MouseDownBackColor = System.Drawing.Color.Transparent; + this.checkBoxMute.FlatAppearance.MouseOverBackColor = System.Drawing.Color.Transparent; + this.checkBoxMute.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.checkBoxMute.ImageIndex = 0; + this.checkBoxMute.ImageList = this.imageList1; + this.checkBoxMute.Location = new System.Drawing.Point(16, 110); + this.checkBoxMute.Name = "checkBoxMute"; + this.checkBoxMute.Size = new System.Drawing.Size(22, 22); + this.checkBoxMute.TabIndex = 15; + this.checkBoxMute.UseVisualStyleBackColor = true; + // + // imageList1 + // + this.imageList1.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageList1.ImageStream"))); + this.imageList1.TransparentColor = System.Drawing.Color.Transparent; + this.imageList1.Images.SetKeyName(0, "sound_mute.png"); + this.imageList1.Images.SetKeyName(1, "sound_none.png"); + this.imageList1.Images.SetKeyName(2, "sound_low.png"); + this.imageList1.Images.SetKeyName(3, "sound.png"); + // + // outputBindingSource + // + this.outputBindingSource.DataSource = typeof(CUEPlayer.Output); + // // Output // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(96, 168); + this.ClientSize = new System.Drawing.Size(74, 136); this.ControlBox = false; + this.Controls.Add(this.checkBoxMute); this.Controls.Add(this.mediaSliderVolume); this.Controls.Add(this.peakMeterCtrl1); - this.Controls.Add(this.buttonPause); - this.Controls.Add(this.buttonPlay); - this.Controls.Add(this.buttonStop); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; this.MaximizeBox = false; this.MinimizeBox = false; @@ -155,6 +155,7 @@ this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; this.Text = "Output"; this.Load += new System.EventHandler(this.Output_Load); + ((System.ComponentModel.ISupportInitialize)(this.outputBindingSource)).EndInit(); this.ResumeLayout(false); } @@ -163,9 +164,9 @@ private MediaSlider.MediaSlider mediaSliderVolume; private Ernzo.WinForms.Controls.PeakMeterCtrl peakMeterCtrl1; - private System.Windows.Forms.Button buttonPause; - private System.Windows.Forms.Button buttonPlay; - private System.Windows.Forms.Button buttonStop; private System.Windows.Forms.Timer timer1; + private System.Windows.Forms.CheckBox checkBoxMute; + private System.Windows.Forms.ImageList imageList1; + private System.Windows.Forms.BindingSource outputBindingSource; } } \ No newline at end of file diff --git a/CUEPlayer/Output.cs b/CUEPlayer/Output.cs index 568ef47..081a0f6 100644 --- a/CUEPlayer/Output.cs +++ b/CUEPlayer/Output.cs @@ -9,24 +9,39 @@ using System.Diagnostics; using NAudio.CoreAudioApi; using CUETools.Codecs; using CUETools.Codecs.CoreAudio; +using CUETools.DSP.Resampler; +using CUETools.DSP.Mixer; using CUETools.Processor; namespace CUEPlayer { public partial class Output : Form { + private IWavePlayer _player; + private AudioBuffer resampled; + private SOXResampler _resampler; private MMDevice _device; + private DateTime _pauseTill; + private bool _muted; - internal MMDevice Device + public int VolumeIcon { get { - return _device; + return _muted ? 0 : mediaSliderVolume.Value < 10 ? 1 : mediaSliderVolume.Value < 50 ? 2 : 3; } + } + public bool Muted + { + get + { + return _muted; + } set { - _device = value; + _muted = value; + _pauseTill = DateTime.Now; } } @@ -35,13 +50,73 @@ namespace CUEPlayer InitializeComponent(); } + private void Output_Load(object sender, EventArgs e) + { + peakMeterCtrl1.Start(50); + outputBindingSource.DataSource = this; + } + public void Init(frmCUEPlayer parent) { MdiParent = parent; _device = WasapiOut.GetDefaultAudioEndpoint(); _device.AudioEndpointVolume.OnVolumeNotification += new AudioEndpointVolumeNotificationDelegate(AudioEndpointVolume_OnVolumeNotification); mediaSliderVolume.Value = (int)(_device.AudioEndpointVolume.MasterVolumeLevelScalar * 100); + //mediaSliderVolume.Maximum = (int)(_device.AudioEndpointVolume.VolumeRange); Show(); + + int delay = 100; + try + { + _player = new WasapiOut(_device, NAudio.CoreAudioApi.AudioClientShareMode.Shared, true, delay, new AudioPCMConfig(32, 2, 44100)); + } + catch + { + _player = null; + } + if (_player == null) + { + try + { + _player = new WasapiOut(_device, NAudio.CoreAudioApi.AudioClientShareMode.Shared, true, delay, new AudioPCMConfig(32, 2, 48000)); + SOXResamplerConfig cfg; + cfg.quality = SOXResamplerQuality.Very; + cfg.phase = 50; + cfg.allow_aliasing = false; + cfg.bandwidth = 0; + _resampler = new SOXResampler(parent.Mixer.PCM, _player.PCM, cfg); + resampled = new AudioBuffer(_player.PCM, parent.Mixer.BufferSize * 2 * parent.Mixer.PCM.SampleRate / _player.PCM.SampleRate); + } + catch (Exception ex) + { + _player = null; + Trace.WriteLine(ex.Message); + } + } + parent.Mixer.AudioRead += new EventHandler(Mixer_AudioRead); + if (_player != null) + _player.Play(); + } + + void Mixer_AudioRead(object sender, AudioReadEventArgs e) + { + if (_muted || _player == null) + { + double tosleep = (_pauseTill - DateTime.Now).TotalMilliseconds; + if (tosleep > 0) System.Threading.Thread.Sleep((int)tosleep); + _pauseTill = DateTime.Now.AddMilliseconds(1000 * e.buffer.Length / e.buffer.PCM.SampleRate); + return; + } + if (_resampler == null) + _player.Write(e.buffer); + else + { + //Trace.WriteLine(string.Format("Flow: {0}", result.Length)); + _resampler.Flow(e.buffer, resampled); + //Trace.WriteLine(string.Format("Play: {0}", resampled.Length)); + if (resampled.Length != 0) + _player.Write(resampled); + } } void AudioEndpointVolume_OnVolumeNotification(AudioVolumeNotificationData data) @@ -51,13 +126,17 @@ namespace CUEPlayer if (this.InvokeRequired) this.Invoke((MethodInvoker)delegate() { AudioEndpointVolume_OnVolumeNotification(data); }); else + { mediaSliderVolume.Value = (int)(data.MasterVolume * 100); + outputBindingSource.ResetBindings(false); + } } private void mediaSliderVolume_Scrolled(object sender, EventArgs e) { try { + outputBindingSource.ResetBindings(false); _device.AudioEndpointVolume.MasterVolumeLevelScalar = mediaSliderVolume.Value / 100.0f; } catch (Exception ex) @@ -82,25 +161,5 @@ namespace CUEPlayer //peakValues[0] = (int)(_device.AudioMeterInformation.MasterPeakValue * 100); peakMeterCtrl1.SetData(peakValues, 0, peakValues.Length); } - - private void buttonPlay_Click(object sender, EventArgs e) - { - (MdiParent as frmCUEPlayer).buttonPlay_Click(sender, e); - } - - private void buttonStop_Click(object sender, EventArgs e) - { - (MdiParent as frmCUEPlayer).buttonStop_Click(sender, e); - } - - private void buttonPause_Click(object sender, EventArgs e) - { - (MdiParent as frmCUEPlayer).buttonPause_Click(sender, e); - } - - private void Output_Load(object sender, EventArgs e) - { - peakMeterCtrl1.Start(50); - } } } diff --git a/CUEPlayer/Output.resx b/CUEPlayer/Output.resx index 93f75a9..8bba917 100644 --- a/CUEPlayer/Output.resx +++ b/CUEPlayer/Output.resx @@ -120,4 +120,63 @@ 17, 17 + + 214, 17 + + + 104, 17 + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj0yLjAuMC4w + LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 + ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAC0 + CgAAAk1TRnQBSQFMAgEBBAEAAQwBAAEEAQABEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo + AwABQAMAASADAAEBAQABCAYAAQgYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA + AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5 + AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA + AWYDAAGZAwABzAIAATMDAAIzAgABMwFmAgABMwGZAgABMwHMAgABMwH/AgABZgMAAWYBMwIAAmYCAAFm + AZkCAAFmAcwCAAFmAf8CAAGZAwABmQEzAgABmQFmAgACmQIAAZkBzAIAAZkB/wIAAcwDAAHMATMCAAHM + AWYCAAHMAZkCAALMAgABzAH/AgAB/wFmAgAB/wGZAgAB/wHMAQABMwH/AgAB/wEAATMBAAEzAQABZgEA + ATMBAAGZAQABMwEAAcwBAAEzAQAB/wEAAf8BMwIAAzMBAAIzAWYBAAIzAZkBAAIzAcwBAAIzAf8BAAEz + AWYCAAEzAWYBMwEAATMCZgEAATMBZgGZAQABMwFmAcwBAAEzAWYB/wEAATMBmQIAATMBmQEzAQABMwGZ + AWYBAAEzApkBAAEzAZkBzAEAATMBmQH/AQABMwHMAgABMwHMATMBAAEzAcwBZgEAATMBzAGZAQABMwLM + AQABMwHMAf8BAAEzAf8BMwEAATMB/wFmAQABMwH/AZkBAAEzAf8BzAEAATMC/wEAAWYDAAFmAQABMwEA + AWYBAAFmAQABZgEAAZkBAAFmAQABzAEAAWYBAAH/AQABZgEzAgABZgIzAQABZgEzAWYBAAFmATMBmQEA + AWYBMwHMAQABZgEzAf8BAAJmAgACZgEzAQADZgEAAmYBmQEAAmYBzAEAAWYBmQIAAWYBmQEzAQABZgGZ + AWYBAAFmApkBAAFmAZkBzAEAAWYBmQH/AQABZgHMAgABZgHMATMBAAFmAcwBmQEAAWYCzAEAAWYBzAH/ + AQABZgH/AgABZgH/ATMBAAFmAf8BmQEAAWYB/wHMAQABzAEAAf8BAAH/AQABzAEAApkCAAGZATMBmQEA + AZkBAAGZAQABmQEAAcwBAAGZAwABmQIzAQABmQEAAWYBAAGZATMBzAEAAZkBAAH/AQABmQFmAgABmQFm + ATMBAAGZATMBZgEAAZkBZgGZAQABmQFmAcwBAAGZATMB/wEAApkBMwEAApkBZgEAA5kBAAKZAcwBAAKZ + Af8BAAGZAcwCAAGZAcwBMwEAAWYBzAFmAQABmQHMAZkBAAGZAswBAAGZAcwB/wEAAZkB/wIAAZkB/wEz + AQABmQHMAWYBAAGZAf8BmQEAAZkB/wHMAQABmQL/AQABzAMAAZkBAAEzAQABzAEAAWYBAAHMAQABmQEA + AcwBAAHMAQABmQEzAgABzAIzAQABzAEzAWYBAAHMATMBmQEAAcwBMwHMAQABzAEzAf8BAAHMAWYCAAHM + AWYBMwEAAZkCZgEAAcwBZgGZAQABzAFmAcwBAAGZAWYB/wEAAcwBmQIAAcwBmQEzAQABzAGZAWYBAAHM + ApkBAAHMAZkBzAEAAcwBmQH/AQACzAIAAswBMwEAAswBZgEAAswBmQEAA8wBAALMAf8BAAHMAf8CAAHM + Af8BMwEAAZkB/wFmAQABzAH/AZkBAAHMAf8BzAEAAcwC/wEAAcwBAAEzAQAB/wEAAWYBAAH/AQABmQEA + AcwBMwIAAf8CMwEAAf8BMwFmAQAB/wEzAZkBAAH/ATMBzAEAAf8BMwH/AQAB/wFmAgAB/wFmATMBAAHM + AmYBAAH/AWYBmQEAAf8BZgHMAQABzAFmAf8BAAH/AZkCAAH/AZkBMwEAAf8BmQFmAQAB/wKZAQAB/wGZ + AcwBAAH/AZkB/wEAAf8BzAIAAf8BzAEzAQAB/wHMAWYBAAH/AcwBmQEAAf8CzAEAAf8BzAH/AQAC/wEz + AQABzAH/AWYBAAL/AZkBAAL/AcwBAAJmAf8BAAFmAf8BZgEAAWYC/wEAAf8CZgEAAf8BZgH/AQAC/wFm + AQABIQEAAaUBAANfAQADdwEAA4YBAAOWAQADywEAA7IBAAPXAQAD3QEAA+MBAAPqAQAD8QEAA/gBAAHw + AfsB/wEAAaQCoAEAA4ADAAH/AgAB/wMAAv8BAAH/AwAB/wEAAf8BAAL/AgAD//8A/wD/AP8AiQAB9AH/ + BAAB8gHsCgAB8gH4DgAB8gH4DgAB8gHsCwAB/wHjAZQB/wEAAf8BvAJtCAAB/wG8Am0MAAH/AbwCbQwA + Af8BvAJtBQABvQH/BQABBwHjARYB8wHsAW0B6wFtBAAD9AHzAewBbQHrAW0IAAP0AfMB7AFtAesBbQQA + Af8DAAP0AfMB7AFtAesBbQQAAb0BRwFvBQAB6wFvARcBbwHrARIB6gFtBAAC6wNtARIB6gFtCAAC6wNt + ARIB6gFtAwABGgH/AwAC6wNtARIB6gFtAwABGgH/AUYBRwEaBAAB7AGSAW8BFwFGARQB6gFtBAAB+AGS + AesBbQESARUB6gFtCAAB+AGSAesBbQESARUB6gFtAgABGgEXARoB/wIAAewBkgHrAW0BEgEVAeoBbQIA + ARoBFwIaAUcBbwQAAewBkgFtAW4BFwFGAm0EAAHsAZIBbQHqARIBEwJtCAAB7AGSAW0B6gESARMCbQEA + AeMB9AIXAwAB7AGSAW0B6gESARMCbQEAAeMB9AIXAQACRgQAAewB9wLsAW8BFwFvAesEAAHsAfcC7AH4 + AesB7AFtCAAB7AH3AuwB+AHrAewBbQEAARYB9AHjARcDAAHsAfcD7AHrAewBbQEAARYB9AHjARcBAAEX + AUYEAAHsAwcBkgFvARcBbwH/AwAB7AMHAZIB7AHtAesIAAHsAwcBkgHsAe0B6wIAARsB4wEaAf8CAAHs + AwcBkgHsAe0B6wIAARsB4wIaARcBFgQAAewD7QH3Ae8BbwEXAZQDAAHsA+0B9wHvAfcB6wgAAewD7QH3 + Ae8B9wHrAwABGwH/AwAB7APtAfcB7wH3AesDAAEbAf8BbwHjARoEAAT0AfcBkgHvAW8BFgH/AgAE9AH3 + AZIB7wH4CAAE9AH3AZIB7wH4BAAB/wMABPQB9wGSAe8B7AQAARoB4wGTCQAB/wHwAuwBGgH/BgAB/wHw + AuwMAAH/AfAC7AwAAf8B8ALsBQABGwH/CwAB8gGSCgAB8gGSDgAB8gGSDgAB8gGSiAABQgFNAT4HAAE+ + AwABKAMAAUADAAEgAwABAQEAAQEGAAEBFgAD/4EAEP8B8wHPAfwB/wH8Af8B/AH/AeEBDwHwAf8B8AH/ + AfAB+QHwAQ8BAAH/AQAB9wEAAfEB8AEPAQAB/wEAAecBAAHgAfABDwEAAf8BAAHDAQABwAHwAQ8BAAH/ + AQABhwEAAYQB8AEPAQAB/wEAAYcBAAGEAfABBwEAAf8BAAHDAQABwAHwAQcBAAH/AQAB5wEAAeAB8AED + AQAB/wEAAfcBAAHxAf8BAwHwAf8B8AH/AfAB+QH/Ac8B/AH/AfwB/wH8Ef8L + + \ No newline at end of file diff --git a/CUEPlayer/Playlist.Designer.cs b/CUEPlayer/Playlist.Designer.cs index ed85e7d..01cb3e8 100644 --- a/CUEPlayer/Playlist.Designer.cs +++ b/CUEPlayer/Playlist.Designer.cs @@ -104,6 +104,7 @@ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.SizableToolWindow; this.Name = "Playlist"; this.Text = "Playlist"; + this.Load += new System.EventHandler(this.Playlist_Load); this.contextMenuStripPlaylist.ResumeLayout(false); this.ResumeLayout(false); diff --git a/CUEPlayer/Playlist.cs b/CUEPlayer/Playlist.cs index fe3b888..96e0438 100644 --- a/CUEPlayer/Playlist.cs +++ b/CUEPlayer/Playlist.cs @@ -33,7 +33,16 @@ namespace CUEPlayer _icon_mgr = parent.IconMgr; listViewTracks.SmallImageList = _icon_mgr.ImageList; foreach (DataSet1.PlaylistRow row in dataSet.Playlist) - listViewTracks.Items.Add(ToItem(row)); + { + try + { + listViewTracks.Items.Add(ToItem(row)); + } + catch (Exception ex) + { + Trace.WriteLine(ex.Message); + } + } } public ListView List @@ -161,5 +170,10 @@ namespace CUEPlayer return; } } + + private void Playlist_Load(object sender, EventArgs e) + { + + } } } diff --git a/CUEPlayer/Properties/AssemblyInfo.cs b/CUEPlayer/Properties/AssemblyInfo.cs index 4fe4bde..8a33b29 100644 --- a/CUEPlayer/Properties/AssemblyInfo.cs +++ b/CUEPlayer/Properties/AssemblyInfo.cs @@ -8,9 +8,9 @@ using System.Runtime.InteropServices; [assembly: AssemblyTitle("CUEPlayer")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyCompany("CUETools")] [assembly: AssemblyProduct("CUEPlayer")] -[assembly: AssemblyCopyright("Copyright © Microsoft 2010")] +[assembly: AssemblyCopyright("Copyright © Gregory S. Chudov 2010")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("2.0.7.0")] +[assembly: AssemblyFileVersion("2.0.7.0")] diff --git a/CUEPlayer/Properties/DataSources/frmCUEPlayer.datasource b/CUEPlayer/Properties/DataSources/frmCUEPlayer.datasource index a71c582..dfd281a 100644 --- a/CUEPlayer/Properties/DataSources/frmCUEPlayer.datasource +++ b/CUEPlayer/Properties/DataSources/frmCUEPlayer.datasource @@ -6,5 +6,5 @@ cause the file to be unrecognizable by the program. --> - CUEPlayer.frmCUEPlayer, CUEPlayer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + CUEPlayer.frmCUEPlayer, CUEPlayer, Version=2.0.7.0, Culture=neutral, PublicKeyToken=null \ No newline at end of file diff --git a/CUEPlayer/Properties/Resources.Designer.cs b/CUEPlayer/Properties/Resources.Designer.cs index 3f6c907..4999a65 100644 --- a/CUEPlayer/Properties/Resources.Designer.cs +++ b/CUEPlayer/Properties/Resources.Designer.cs @@ -60,6 +60,13 @@ namespace CUEPlayer.Properties { } } + internal static System.Drawing.Bitmap cog { + get { + object obj = ResourceManager.GetObject("cog", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + internal static System.Drawing.Bitmap control_eject { get { object obj = ResourceManager.GetObject("control_eject", resourceCulture); @@ -143,5 +150,26 @@ namespace CUEPlayer.Properties { return ((System.Drawing.Bitmap)(obj)); } } + + internal static System.Drawing.Bitmap sound { + get { + object obj = ResourceManager.GetObject("sound", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap sound_mute { + get { + object obj = ResourceManager.GetObject("sound_mute", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap transmit_blue { + get { + object obj = ResourceManager.GetObject("transmit_blue", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } } } diff --git a/CUEPlayer/Properties/Resources.resx b/CUEPlayer/Properties/Resources.resx index ca47dd6..b489aee 100644 --- a/CUEPlayer/Properties/Resources.resx +++ b/CUEPlayer/Properties/Resources.resx @@ -118,8 +118,8 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - ..\Resources\control_eject_blue.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\ctdb.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a ..\Resources\control_fastforward_blue.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a @@ -130,20 +130,32 @@ ..\Resources\control_eject.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\control_end_blue.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\control_eject_blue.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\control_stop_blue.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\sound_mute.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a ..\Resources\control_repeat_blue.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\sound.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + ..\Resources\control_rewind_blue.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\transmit_blue.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + ..\Resources\control_pause_blue.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\control_stop_blue.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\control_end_blue.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a ..\Resources\control_play_blue.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a @@ -151,7 +163,7 @@ ..\Resources\control_equalizer_blue.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\ctdb.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\cog.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a \ No newline at end of file diff --git a/CUEPlayer/Properties/Settings.Designer.cs b/CUEPlayer/Properties/Settings.Designer.cs index adad87b..1af32be 100644 --- a/CUEPlayer/Properties/Settings.Designer.cs +++ b/CUEPlayer/Properties/Settings.Designer.cs @@ -32,5 +32,27 @@ namespace CUEPlayer.Properties { return ((string)(this["CUEPlayerConnectionString"])); } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public global::CUETools.Codecs.Icecast.IcecastSettingsData IcecastSettings { + get { + return ((global::CUETools.Codecs.Icecast.IcecastSettingsData)(this["IcecastSettings"])); + } + set { + this["IcecastSettings"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public global::CUEPlayer.CUEPlayerSettings AppSettings { + get { + return ((global::CUEPlayer.CUEPlayerSettings)(this["AppSettings"])); + } + set { + this["AppSettings"] = value; + } + } } } diff --git a/CUEPlayer/Properties/Settings.settings b/CUEPlayer/Properties/Settings.settings index c35c471..6289b05 100644 --- a/CUEPlayer/Properties/Settings.settings +++ b/CUEPlayer/Properties/Settings.settings @@ -10,5 +10,11 @@ </SerializableConnectionString> Data Source=|DataDirectory|\CUEPlayer.sdf + + + + + + \ No newline at end of file diff --git a/CUEPlayer/Resources/cog.png b/CUEPlayer/Resources/cog.png new file mode 100644 index 0000000..67de2c6 Binary files /dev/null and b/CUEPlayer/Resources/cog.png differ diff --git a/CUEPlayer/Resources/sound.png b/CUEPlayer/Resources/sound.png new file mode 100644 index 0000000..6056d23 Binary files /dev/null and b/CUEPlayer/Resources/sound.png differ diff --git a/CUEPlayer/Resources/sound_low.png b/CUEPlayer/Resources/sound_low.png new file mode 100644 index 0000000..4d91863 Binary files /dev/null and b/CUEPlayer/Resources/sound_low.png differ diff --git a/CUEPlayer/Resources/sound_mute.png b/CUEPlayer/Resources/sound_mute.png new file mode 100644 index 0000000..b652d2a Binary files /dev/null and b/CUEPlayer/Resources/sound_mute.png differ diff --git a/CUEPlayer/Resources/sound_none.png b/CUEPlayer/Resources/sound_none.png new file mode 100644 index 0000000..b497ebd Binary files /dev/null and b/CUEPlayer/Resources/sound_none.png differ diff --git a/CUEPlayer/Resources/transmit_blue.ico b/CUEPlayer/Resources/transmit_blue.ico new file mode 100644 index 0000000..533f9e7 Binary files /dev/null and b/CUEPlayer/Resources/transmit_blue.ico differ diff --git a/CUEPlayer/Resources/transmit_blue.png b/CUEPlayer/Resources/transmit_blue.png new file mode 100644 index 0000000..7b1142f Binary files /dev/null and b/CUEPlayer/Resources/transmit_blue.png differ diff --git a/CUEPlayer/Settings.cs b/CUEPlayer/Settings.cs new file mode 100644 index 0000000..9d26791 --- /dev/null +++ b/CUEPlayer/Settings.cs @@ -0,0 +1,28 @@ +namespace CUEPlayer.Properties { + + + // This class allows you to handle specific events on the settings class: + // The SettingChanging event is raised before a setting's value is changed. + // The PropertyChanged event is raised after a setting's value is changed. + // The SettingsLoaded event is raised after the setting values are loaded. + // The SettingsSaving event is raised before the setting values are saved. + internal sealed partial class Settings { + + public Settings() { + // // To add event handlers for saving and changing settings, uncomment the lines below: + // + // this.SettingChanging += this.SettingChangingEventHandler; + // + // this.SettingsSaving += this.SettingsSavingEventHandler; + // + } + + private void SettingChangingEventHandler(object sender, System.Configuration.SettingChangingEventArgs e) { + // Add code to handle the SettingChangingEvent event here. + } + + private void SettingsSavingEventHandler(object sender, System.ComponentModel.CancelEventArgs e) { + // Add code to handle the SettingsSaving event here. + } + } +} diff --git a/CUEPlayer/app.config b/CUEPlayer/app.config index b579cd0..d979376 100644 --- a/CUEPlayer/app.config +++ b/CUEPlayer/app.config @@ -7,4 +7,9 @@ connectionString="Data Source=|DataDirectory|\CUEPlayer.sdf" providerName="Microsoft.SqlServerCe.Client.3.5" /> + + + + + \ No newline at end of file diff --git a/CUEPlayer/frmCUEPlayer.Designer.cs b/CUEPlayer/frmCUEPlayer.Designer.cs index dd6e041..3df6216 100644 --- a/CUEPlayer/frmCUEPlayer.Designer.cs +++ b/CUEPlayer/frmCUEPlayer.Designer.cs @@ -28,24 +28,62 @@ /// private void InitializeComponent() { + this.menuStrip1 = new System.Windows.Forms.MenuStrip(); + this.windowsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.icecastToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.menuStrip1.SuspendLayout(); this.SuspendLayout(); // + // menuStrip1 + // + this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.windowsToolStripMenuItem}); + this.menuStrip1.Location = new System.Drawing.Point(0, 0); + this.menuStrip1.Name = "menuStrip1"; + this.menuStrip1.Size = new System.Drawing.Size(1200, 24); + this.menuStrip1.TabIndex = 1; + this.menuStrip1.Text = "menuStrip1"; + // + // windowsToolStripMenuItem + // + this.windowsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.icecastToolStripMenuItem}); + this.windowsToolStripMenuItem.Name = "windowsToolStripMenuItem"; + this.windowsToolStripMenuItem.Size = new System.Drawing.Size(68, 20); + this.windowsToolStripMenuItem.Text = "Windows"; + // + // icecastToolStripMenuItem + // + this.icecastToolStripMenuItem.Name = "icecastToolStripMenuItem"; + this.icecastToolStripMenuItem.Size = new System.Drawing.Size(152, 22); + this.icecastToolStripMenuItem.Text = "Icecast"; + this.icecastToolStripMenuItem.Click += new System.EventHandler(this.icecastToolStripMenuItem_Click); + // // frmCUEPlayer // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(1200, 477); + this.ClientSize = new System.Drawing.Size(1200, 474); + this.Controls.Add(this.menuStrip1); this.IsMdiContainer = true; + this.MainMenuStrip = this.menuStrip1; this.Name = "frmCUEPlayer"; this.Text = "CUEPlayer 2.0.7"; this.Load += new System.EventHandler(this.frmCUEPlayer_Load); this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.frmCUEPlayer_FormClosing); + this.menuStrip1.ResumeLayout(false); + this.menuStrip1.PerformLayout(); this.ResumeLayout(false); + this.PerformLayout(); } #endregion + private System.Windows.Forms.MenuStrip menuStrip1; + private System.Windows.Forms.ToolStripMenuItem windowsToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem icecastToolStripMenuItem; + } } diff --git a/CUEPlayer/frmCUEPlayer.cs b/CUEPlayer/frmCUEPlayer.cs index 109497f..23e53aa 100644 --- a/CUEPlayer/frmCUEPlayer.cs +++ b/CUEPlayer/frmCUEPlayer.cs @@ -8,12 +8,9 @@ using System.IO; using System.Threading; using System.Windows.Forms; using System.Diagnostics; -using NAudio.CoreAudioApi; using CUEControls; using CUETools.Codecs; -using CUETools.Codecs.CoreAudio; using CUETools.DSP.Mixer; -using CUETools.DSP.Resampler; using CUETools.Processor; namespace CUEPlayer @@ -22,12 +19,10 @@ namespace CUEPlayer { private ShellIconMgr _icon_mgr; private CUEConfig _config; - private IWavePlayer _player; DataSet1TableAdapters.PlaylistTableAdapter adapterPlayList = new DataSet1TableAdapters.PlaylistTableAdapter(); private DataSet1 dataSet = new DataSet1(); private Thread mixThread; private MixingSource _mixer; - private SOXResampler _resampler; internal Playlist wndPlaylist { @@ -85,236 +80,42 @@ namespace CUEPlayer private void frmCUEPlayer_Load(object sender, EventArgs e) { - int delay = 100; - AudioPCMConfig mixerPCM = AudioPCMConfig.RedBook; + if (Properties.Settings.Default.AppSettings == null) + { + Properties.Settings.Default.AppSettings = new CUEPlayerSettings(); + Properties.Settings.Default.AppSettings.IcecastServers.Add(new CUETools.Codecs.Icecast.IcecastSettingsData()); + } //System.Data.SqlServerCe.SqlCeDataAdapter ad = new System.Data.SqlServerCe.SqlCeDataAdapter(); //ad.SelectCommand = new System.Data.SqlServerCe.SqlCeCommand("SELECT * FROM Playlist WHERE track=1", adapterPlayList.Connection); //ad.Fill(dataSet.Playlist); adapterPlayList.Fill(dataSet.Playlist); - _mixer = new MixingSource(mixerPCM, delay, 2); + _mixer = new MixingSource(new AudioPCMConfig(32, 2, 44100), 100, 2); outputA.Init(this); browser.Init(this); playlist.Init(this); deckB.Init(this, null); deckA.Init(this, deckB); + Icecast icecast = new Icecast(); + icecast.Init(this); //LayoutMdi(MdiLayout.TileHorizontal); - + browser.Location = new Point(0, 0); - browser.Height = ClientRectangle.Height - 5; + browser.Height = ClientRectangle.Height - 5 - menuStrip1.Height; playlist.Location = new Point(browser.Location.X + browser.Width, 0); - playlist.Height = ClientRectangle.Height - 5; + playlist.Height = ClientRectangle.Height - 5 - menuStrip1.Height; deckA.Location = new Point(playlist.Location.X + playlist.Width, 0); deckB.Location = new Point(playlist.Location.X + playlist.Width, deckA.Height); outputA.Location = new Point(deckA.Location.X + deckA.Width, 0); + icecast.Location = new Point(deckA.Location.X + deckA.Width, outputA.Height); - try - { - _player = new WasapiOut(outputA.Device, NAudio.CoreAudioApi.AudioClientShareMode.Shared, true, delay, new AudioPCMConfig(32, 2, 44100)); - } - catch - { - _player = null; - } - if (_player == null) - { - try - { - _player = new WasapiOut(outputA.Device, NAudio.CoreAudioApi.AudioClientShareMode.Shared, true, delay, new AudioPCMConfig(32, 2, 48000)); - SOXResamplerConfig cfg; - cfg.quality = SOXResamplerQuality.Very; - cfg.phase = 50; - cfg.allow_aliasing = false; - cfg.bandwidth = 0; - _resampler = new SOXResampler(mixerPCM, _player.PCM, cfg); - } - catch(Exception ex) - { - _player = null; - Trace.WriteLine(ex.Message); - } - } - if (_player != null) - { - _player.Play(); - - mixThread = new Thread(MixThread); - mixThread.Priority = ThreadPriority.AboveNormal; - mixThread.IsBackground = true; - mixThread.Name = "Mixer"; - mixThread.Start(); - } - } - - Thread playThread; - - int playingRow; - - private void PlayThread() - { - AudioBuffer buff = new AudioBuffer(AudioPCMConfig.RedBook, 0x2000); - IAudioSource playingSource = null; - CUESheet playingCue = null; - long playingOffs = 0; - long playingFin = 0; - - try - { - do - { - // End of playlist entry or source file - if (playingSource != null && (playingOffs == playingFin || playingSource.Remaining == 0)) - { - this.Invoke((MethodInvoker)delegate() - { - playlist.List.Items[playingRow].BackColor = Color.White; - }); - playingRow++; - playingOffs = 0; - if (playingRow >= dataSet.Playlist.Rows.Count) - break; - string path = dataSet.Playlist[playingRow].path; - int track = dataSet.Playlist[playingRow].track; - - if (playingCue == null || - playingSource == null || - playingCue.InputPath != path || - playingSource.Position != (long)playingCue.TOC[track].Start * 588) - { - if (playingSource != null) - { - playingSource.Close(); - playingSource = null; - } - if (playingCue != null) - { - playingCue.Close(); - playingCue = null; - } - } - else - { - playingFin = (long)playingCue.TOC[track].Length * 588; - this.Invoke((MethodInvoker)delegate() - { - playlist.List.Items[playingRow].BackColor = Color.AliceBlue; - //deckA.UpdateDeck(dataSet, playingRow, playingCue, playingFin); - }); - } - } - // Open it - if (playingSource == null) - { - string path = dataSet.Playlist[playingRow].path; - int track = dataSet.Playlist[playingRow].track; - - try - { - playingCue = new CUESheet(_config); - playingCue.Open(path); - playingSource = new CUESheetAudio(playingCue); - playingSource.Position = (long)playingCue.TOC[track].Start * 588 + playingOffs; - playingSource = new AudioPipe(playingSource, 0x2000); - playingFin = (long)playingCue.TOC[track].Length * 588; - this.Invoke((MethodInvoker)delegate() - { - playlist.List.Items[playingRow].BackColor = Color.AliceBlue; - //deckA.UpdateDeck(dataSet, playingRow, playingCue, playingFin); - }); - } - catch (Exception ex) - { - // skip it - playingOffs = playingFin = 0; - continue; - } - } - playingSource.Read(buff, (int)(playingFin - playingOffs)); - - this.Invoke((MethodInvoker)delegate() - { - deckA.PlayingOffset = (int)playingOffs; - }); - - _player.Write(buff); - playingOffs += buff.Length; - } while (_player.PlaybackState != PlaybackState.Stopped); - } - catch (Exception ex) - { - // Can't invoke while joining - - //if (playingRow < dataSet.Playlist.Rows.Count) - // this.Invoke((MethodInvoker)delegate() - // { - // listViewTracks.Items[playingRow].BackColor = Color.White; - // }); - } - - if (playingCue != null) - { - playingCue.Close(); - playingCue = null; - } - if (playingSource != null) - { - playingSource.Close(); - playingSource = null; - } - } - - internal void buttonPlay_Click(object sender, EventArgs e) - { - try - { - _player.Stop(); - if (playThread != null) - { - playThread.Join(); - playThread = null; - } - - if (playlist.List.SelectedIndices.Count < 0) - return; - - playingRow = playlist.List.SelectedIndices[0]; - playlist.List.Items[playingRow].BackColor = Color.AliceBlue; - - _player.Play(); - - playThread = new Thread(new ThreadStart(PlayThread)); - playThread.Priority = ThreadPriority.AboveNormal; - playThread.IsBackground = true; - playThread.Start(); - } - catch (Exception ex) - { - Trace.WriteLine(ex.Message); - } - } - - internal void buttonStop_Click(object sender, EventArgs e) - { - try - { - _player.Stop(); - if (playThread != null) - { - playThread.Join(); - playThread = null; - } - } - catch (Exception ex) - { - Trace.WriteLine(ex.Message); - } - } - - internal void buttonPause_Click(object sender, EventArgs e) - { - _player.Pause(); + mixThread = new Thread(MixThread); + mixThread.Priority = ThreadPriority.AboveNormal; + mixThread.IsBackground = true; + mixThread.Name = "Mixer"; + mixThread.Start(); } private void frmCUEPlayer_FormClosing(object sender, FormClosingEventArgs e) @@ -331,23 +132,55 @@ namespace CUEPlayer private void MixThread() { - AudioBuffer result = new AudioBuffer( - new AudioPCMConfig(_player.PCM.BitsPerSample, _player.PCM.ChannelCount, _mixer.PCM.SampleRate), _mixer.BufferSize); - AudioBuffer resampled = _resampler == null ? null : new AudioBuffer(_player.PCM, _mixer.BufferSize * 2 * _mixer.PCM.SampleRate / _player.PCM.SampleRate); + AudioBuffer result = new AudioBuffer(_mixer.PCM, _mixer.BufferSize); while (true) { - //Trace.WriteLine(string.Format("Read")); _mixer.Read(result, -1); - if (_resampler == null) - _player.Write(result); - else - { - //Trace.WriteLine(string.Format("Flow: {0}", result.Length)); - _resampler.Flow(result, resampled); - //Trace.WriteLine(string.Format("Play: {0}", resampled.Length)); - if (resampled.Length != 0) - _player.Write(resampled); - } + } + } + + public event EventHandler updateMetadata; + + public void UpdateMetadata(string artist, string title) + { + UpdateMetadataEvent e = new UpdateMetadataEvent(); + e.artist = artist; + e.title = title; + if (updateMetadata != null) + updateMetadata(this, e); + } + + private void icecastToolStripMenuItem_Click(object sender, EventArgs e) + { + Icecast icecast = new Icecast(); + icecast.Init(this); + } + } + + public class UpdateMetadataEvent: EventArgs + { + public string artist; + public string title; + } + + public class CUEPlayerSettings + { + private BindingList icecastServers; + + public CUEPlayerSettings() + { + icecastServers = new BindingList(); + } + + public BindingList IcecastServers + { + get + { + return icecastServers; + } + set + { + icecastServers = value; } } } diff --git a/CUEPlayer/frmCUEPlayer.resx b/CUEPlayer/frmCUEPlayer.resx index e5c789f..87b404d 100644 --- a/CUEPlayer/frmCUEPlayer.resx +++ b/CUEPlayer/frmCUEPlayer.resx @@ -117,6 +117,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + 17, 17 + 39 diff --git a/CUETools.Codecs.FLAKE/FlakeWriter.cs b/CUETools.Codecs.FLAKE/FlakeWriter.cs index db60b46..cee78b5 100644 --- a/CUETools.Codecs.FLAKE/FlakeWriter.cs +++ b/CUETools.Codecs.FLAKE/FlakeWriter.cs @@ -1502,9 +1502,11 @@ namespace CUETools.Codecs.FLAKE if (bs < eparams.block_size) { - fixed (int* s = samplesBuffer) - for (int ch = 0; ch < channels; ch++) - AudioSamples.MemCpy(s + ch * Flake.MAX_BLOCKSIZE, s + bs + ch * Flake.MAX_BLOCKSIZE, eparams.block_size - bs); + for (int ch = 0; ch < (channels == 2 ? 4 : channels); ch++) + Buffer.BlockCopy(samplesBuffer, (bs + ch * Flake.MAX_BLOCKSIZE) * sizeof(int), samplesBuffer, ch * Flake.MAX_BLOCKSIZE * sizeof(int), (eparams.block_size - bs) * sizeof(int)); + //fixed (int* s = samplesBuffer) + // for (int ch = 0; ch < channels; ch++) + // AudioSamples.MemCpy(s + ch * Flake.MAX_BLOCKSIZE, s + bs + ch * Flake.MAX_BLOCKSIZE, eparams.block_size - bs); } samplesInBuffer -= bs; diff --git a/CUETools.Codecs.Icecast/CUETools.Codecs.Icecast.csproj b/CUETools.Codecs.Icecast/CUETools.Codecs.Icecast.csproj new file mode 100644 index 0000000..d2e7e3a --- /dev/null +++ b/CUETools.Codecs.Icecast/CUETools.Codecs.Icecast.csproj @@ -0,0 +1,61 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {8FC5DA7C-F6AC-4D04-85BC-1233DDF569E7} + Library + Properties + CUETools.Codecs.Icecast + CUETools.Codecs.Icecast + v2.0 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + {1AF02E2C-2CB2-44B5-B417-37653071FEC6} + CUETools.Codecs.LAME + False + + + {6458A13A-30EF-45A9-9D58-E5031B17BEE2} + CUETools.Codecs + + + + + \ No newline at end of file diff --git a/CUETools.Codecs.Icecast/IcecastWriter.cs b/CUETools.Codecs.Icecast/IcecastWriter.cs new file mode 100644 index 0000000..a93522d --- /dev/null +++ b/CUETools.Codecs.Icecast/IcecastWriter.cs @@ -0,0 +1,264 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Net; +using System.IO; +using System.Web; +using CUETools.Codecs; + +namespace CUETools.Codecs.Icecast +{ + public class IcecastWriter: IAudioDest + { + private long _sampleOffset = 0; + private AudioPCMConfig pcm = AudioPCMConfig.RedBook; + private LAME.LAMEEncoderCBR encoder = null; + private HttpWebRequest req = null; + private HttpWebResponse resp = null; + private Stream reqStream; + private IcecastSettingsData settings = null; + + public IAudioDest Encoder + { + get + { + return encoder; + } + } + + public IcecastWriter(AudioPCMConfig pcm, IcecastSettingsData settings) + { + this.pcm = pcm; + this.settings = settings; + } + + #region IAudioDest Members + + public HttpWebResponse Response + { + get + { + return resp; + } + } + + public void Connect() + { + Uri uri = new Uri("http://" + settings.Server + ":" + settings.Port + settings.Mount); + req = (HttpWebRequest)WebRequest.Create(uri); + //req.Proxy = proxy; + //req.UserAgent = userAgent; + req.ProtocolVersion = HttpVersion.Version10; // new Version("ICE/1.0"); + req.Method = "SOURCE"; + req.ContentType = "audio/mpeg"; + req.Headers.Add("ice-name", settings.Name ?? "no name"); + req.Headers.Add("ice-public", "1"); + if ((settings.Url ?? "") != "") req.Headers.Add("ice-url", settings.Url); + if ((settings.Genre ?? "") != "") req.Headers.Add("ice-genre", settings.Genre); + if ((settings.Desctiption ?? "") != "") req.Headers.Add("ice-description", settings.Desctiption); + req.Headers.Add("Authorization", string.Format("Basic {0}", Convert.ToBase64String(Encoding.ASCII.GetBytes(string.Format("source:{0}", settings.Password))))); + req.Timeout = System.Threading.Timeout.Infinite; + req.ReadWriteTimeout = System.Threading.Timeout.Infinite; + //req.ContentLength = 999999999; + req.KeepAlive = false; + req.SendChunked = true; + req.AllowWriteStreamBuffering = false; + req.CachePolicy = new System.Net.Cache.HttpRequestCachePolicy(System.Net.Cache.HttpRequestCacheLevel.BypassCache); + + System.Reflection.PropertyInfo pi = typeof(ServicePoint).GetProperty("HttpBehaviour", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); + pi.SetValue(req.ServicePoint, pi.PropertyType.GetField("Unknown").GetValue(null), null); + + reqStream = req.GetRequestStream(); + + System.Reflection.FieldInfo fi = reqStream.GetType().GetField("m_HttpWriteMode", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); + fi.SetValue(reqStream, fi.FieldType.GetField("Buffer").GetValue(null)); + System.Reflection.MethodInfo mi = reqStream.GetType().GetMethod("CallDone", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic, null, new Type[0], null); + mi.Invoke(reqStream, null); + + try + { + resp = req.GetResponse() as HttpWebResponse; + if (resp.StatusCode == HttpStatusCode.OK) + { + encoder = new CUETools.Codecs.LAME.LAMEEncoderCBR("", reqStream, AudioPCMConfig.RedBook); + encoder.Options = settings.MP3Options; + } + } + catch (WebException ex) + { + if (ex.Status == WebExceptionStatus.ProtocolError) + resp = ex.Response as HttpWebResponse; + else + throw ex; + } + } + + public void UpdateMetadata(string artist, string title) + { + string song = ((artist ?? "") != "" && (title ?? "") != "") ? artist + " - " + title : (title ?? ""); + string metadata = ""; + //if (station != "") + // metadata += "&name=" + Uri.EscapeDataString(station); + if (song != "") + metadata += "&song=" + Uri.EscapeDataString(song); + Uri uri = new Uri("http://" + settings.Server + ":" + settings.Port + "/admin/metadata?mode=updinfo&mount=" + settings.Mount + metadata); + HttpWebRequest req2 = (HttpWebRequest)WebRequest.Create(uri); + req2.Method = "GET"; + req2.Credentials = new NetworkCredential("source", settings.Password); + //req.Proxy = proxy; + //req.UserAgent = userAgent; + //req2.Headers.Add("Authorization", string.Format("Basic {0}", Convert.ToBase64String(Encoding.ASCII.GetBytes(string.Format("source:{0}", settings.Password))))); + HttpStatusCode accResult = HttpStatusCode.OK; + try + { + HttpWebResponse resp = (HttpWebResponse)req2.GetResponse(); + accResult = resp.StatusCode; + if (accResult == HttpStatusCode.OK) + { + } + resp.Close(); + } + catch (WebException ex) + { + if (ex.Status == WebExceptionStatus.ProtocolError) + accResult = ((HttpWebResponse)ex.Response).StatusCode; + else + accResult = HttpStatusCode.BadRequest; + } + } + + public void Close() + { + if (encoder != null) + { + encoder.Close(); + encoder = null; + } + if (reqStream != null) + { + reqStream.Close(); + reqStream = null; + } + if (resp != null) + { + resp.Close(); + resp = null; + } + if (req != null) + { + req.Abort(); + req = null; + } + } + + public void Delete() + { + if (encoder != null) + { + encoder.Delete(); + encoder = null; + } + if (reqStream != null) + { + reqStream.Close(); + reqStream = null; + } + if (resp != null) + { + resp.Close(); + resp = null; + } + if (req != null) + { + req.Abort(); + req = null; + } + } + + AudioBuffer tmp; + + public void Write(AudioBuffer src) + { + if (encoder == null) + throw new Exception("not connected"); + + if (tmp == null || tmp.Size < src.Size) + tmp = new AudioBuffer(AudioPCMConfig.RedBook, src.Size); + tmp.Prepare(-1); + Buffer.BlockCopy(src.Float, 0, tmp.Float, 0, src.Length * 8); + tmp.Length = src.Length; + encoder.Write(tmp); + } + + public long Position + { + get + { + return _sampleOffset; + } + } + + public long BlockSize + { + set { } + } + + public long FinalSampleCount + { + set { ; } + } + + public int CompressionLevel + { + get { return 0; } + set { } + } + + public string Options + { + set + { + if (value == null || value == "") return; + throw new Exception("Unsupported options " + value); + } + } + public AudioPCMConfig PCM + { + get { return pcm; } + } + + public string Path { get { return null; } } + #endregion + + public long BytesWritten + { + get + { + return encoder == null ? 0 : encoder.BytesWritten; + } + } + } + + public class IcecastSettingsData + { + private string server; + private string port = "8000"; + private string password; + private string mount; + private string name; + private string description; + private string url; + private string genre; + private string mp3Options = "-m j -b 192"; + + public string Server { get { return server; } set { server = value; } } + public string Port { get { return port; } set { port = value; } } + public string Password { get { return password; } set { password = value; } } + public string Mount { get { return mount; } set { mount = value; } } + public string Name { get { return name; } set { name = value; } } + public string Desctiption { get { return description; } set { description = value; } } + public string Url { get { return url; } set { url = value; } } + public string Genre { get { return genre; } set { genre = value; } } + public string MP3Options { get { return mp3Options; } set { mp3Options = value; } } + } +} diff --git a/CUETools.Codecs.Icecast/Properties/AssemblyInfo.cs b/CUETools.Codecs.Icecast/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..d0568ae --- /dev/null +++ b/CUETools.Codecs.Icecast/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CUETools.Codecs.Icecast")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("CUETools.Codecs.Icecast")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2010")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("913f32e1-64c8-45d3-8f91-5dd1ba733fe9")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/CUETools.Codecs.LAME/Encoder.cs b/CUETools.Codecs.LAME/Encoder.cs index 00fe2f8..a608d6d 100644 --- a/CUETools.Codecs.LAME/Encoder.cs +++ b/CUETools.Codecs.LAME/Encoder.cs @@ -20,9 +20,12 @@ namespace CUETools.Codecs.LAME private string _path; private Stream _IO; private long position = 0, sample_count = -1; + private long bytesWritten = 0; public LAMEEncoder(string path, Stream IO, AudioPCMConfig pcm) { + if (pcm.BitsPerSample != 16)// && pcm.BitsPerSample != 32) + throw new ArgumentOutOfRangeException("format", "Only 16 & 32 bits samples supported"); _pcm = pcm; _path = path; _IO = IO; @@ -33,45 +36,50 @@ namespace CUETools.Codecs.LAME { } - public void DeInit() + public void DeInit(bool flush) { if (!inited || closed) return; try { - uint EncodedSize = 0; - if (m_InBufferPos > 0) + if (flush) { - if (Lame_encDll.EncodeChunk(m_hLameStream, m_InBuffer, 0, (uint)m_InBufferPos, m_OutBuffer, ref EncodedSize) == Lame_encDll.BE_ERR_SUCCESSFUL) + uint EncodedSize = 0; + if (m_InBufferPos > 0) + { + if (Lame_encDll.EncodeChunk(m_hLameStream, m_InBuffer, 0, (uint)m_InBufferPos, m_OutBuffer, ref EncodedSize) == Lame_encDll.BE_ERR_SUCCESSFUL) + { + if (EncodedSize > 0) + { + _IO.Write(m_OutBuffer, 0, (int)EncodedSize); + bytesWritten += EncodedSize; + } + } + } + EncodedSize = 0; + if (Lame_encDll.beDeinitStream(m_hLameStream, m_OutBuffer, ref EncodedSize) == Lame_encDll.BE_ERR_SUCCESSFUL) { if (EncodedSize > 0) { _IO.Write(m_OutBuffer, 0, (int)EncodedSize); + bytesWritten += EncodedSize; } } } - EncodedSize = 0; - if (Lame_encDll.beDeinitStream(m_hLameStream, m_OutBuffer, ref EncodedSize) == Lame_encDll.BE_ERR_SUCCESSFUL) - { - if (EncodedSize > 0) - { - _IO.Write(m_OutBuffer, 0, (int)EncodedSize); - } - } } finally { Lame_encDll.beCloseStream(m_hLameStream); _IO.Close(); - } - closed = true; + closed = true; + } } public void Close() { bool needTag = !closed && _path != null && _path != ""; - DeInit(); + DeInit(true); if (needTag) { try @@ -88,7 +96,7 @@ namespace CUETools.Codecs.LAME { if (!closed) { - DeInit(); + DeInit(false); if (_path != "") File.Delete(_path); } @@ -150,6 +158,7 @@ namespace CUETools.Codecs.LAME if (EncodedSize > 0) { _IO.Write(m_OutBuffer, 0, (int)EncodedSize); + bytesWritten += EncodedSize; } } else @@ -167,6 +176,7 @@ namespace CUETools.Codecs.LAME if (EncodedSize > 0) { _IO.Write(m_OutBuffer, 0, (int)EncodedSize); + bytesWritten += EncodedSize; } } else @@ -234,6 +244,14 @@ namespace CUETools.Codecs.LAME } public string Path { get { return _path; } } + + public long BytesWritten + { + get + { + return bytesWritten; + } + } } @@ -304,8 +322,9 @@ namespace CUETools.Codecs.LAME [AudioEncoderClass("lame CBR", "mp3", false, "96 128 192 256 320", "256", 2)] public class LAMEEncoderCBR : LAMEEncoder { - private int bps_index; + private uint bps; private static readonly uint[] bps_table = new uint[] {96, 128, 192, 256, 320}; + private MpegMode stereo = MpegMode.STEREO; public LAMEEncoderCBR(string path, Stream IO, AudioPCMConfig pcm) : base(path, IO, pcm) @@ -321,20 +340,55 @@ namespace CUETools.Codecs.LAME { get { - return bps_index; + for (int i = 0; i < bps_table.Length; i++) + if (bps == bps_table[i]) + return i; + return -1; } set { if (value < 0 || value > bps_table.Length) throw new Exception("unsupported compression level"); - bps_index = value; + bps = bps_table[value]; + } + } + + public override string Options + { + set + { + if (value == null || value == "") return; + string[] args = value.Split(); + for (int i = 0; i < args.Length; i++) + { + if (args[i] == "-b" && (++i) < args.Length) + { + bps = uint.Parse(args[i]); + continue; + } + if (args[i] == "-m" && (++i) < args.Length) + { + switch (args[i]) + { + case "s": stereo = MpegMode.STEREO; break; + case "j": stereo = MpegMode.JOINT_STEREO; break; + case "d": stereo = MpegMode.DUAL_CHANNEL; break; + case "m": stereo = MpegMode.MONO; break; + default: + throw new Exception("Unsupported options " + value); + } + continue; + } + throw new Exception("Unsupported options " + value); + } } } protected override BE_CONFIG MakeConfig() { - BE_CONFIG Mp3Config = new BE_CONFIG(PCM, bps_table[bps_index]); + BE_CONFIG Mp3Config = new BE_CONFIG(PCM, bps); Mp3Config.format.lhv1.bWriteVBRHeader = 1; + Mp3Config.format.lhv1.nMode = stereo; //Mp3Config.format.lhv1.nVbrMethod = VBRMETHOD.VBR_METHOD_NONE; // --cbr //Mp3Config.format.lhv1.nPreset = LAME_QUALITY_PRESET.LQP_NORMAL_QUALITY; return Mp3Config; diff --git a/CUETools.Codecs.LAME/Lame.cs b/CUETools.Codecs.LAME/Lame.cs index 3a887a5..44b434f 100644 --- a/CUETools.Codecs.LAME/Lame.cs +++ b/CUETools.Codecs.LAME/Lame.cs @@ -139,9 +139,6 @@ namespace CUETools.Codecs.LAME public LHV1(AudioPCMConfig format, uint MpeBitRate) { - if ( format.BitsPerSample != 16) - throw new ArgumentOutOfRangeException("format", "Only 16 bits samples supported"); - dwStructVersion = 1; dwStructSize = (uint)Marshal.SizeOf(typeof(BE_CONFIG)); switch (format.SampleRate) diff --git a/CUETools.Codecs/Codecs.cs b/CUETools.Codecs/Codecs.cs index b7d4b5e..41e14a3 100644 --- a/CUETools.Codecs/Codecs.cs +++ b/CUETools.Codecs/Codecs.cs @@ -250,6 +250,8 @@ namespace CUETools.Codecs Bytes16ToFloat(bytes, 0, fsamples, 0, length, pcm.ChannelCount); //else if (pcm.BitsPerSample > 16 && PCM.BitsPerSample <= 24) // BytesToFLACSamples_24(bytes, 0, fsamples, 0, length, pcm.ChannelCount, 24 - pcm.BitsPerSample); + else if (pcm.BitsPerSample == 32) + Buffer.BlockCopy(bytes, 0, fsamples, 0, length * 4 * pcm.ChannelCount); else throw new Exception("Unsupported bitsPerSample value"); } @@ -356,6 +358,16 @@ namespace CUETools.Codecs throw new Exception("Invalid length"); } + internal unsafe void Load(int dstOffset, AudioBuffer src, int srcOffset, int copyLength) + { + if (dataInBytes) + Buffer.BlockCopy(src.Bytes, srcOffset * pcm.BlockAlign, Bytes, dstOffset * pcm.BlockAlign, copyLength * pcm.BlockAlign); + if (dataInSamples) + Buffer.BlockCopy(src.Samples, srcOffset * pcm.ChannelCount * 4, Samples, dstOffset * pcm.ChannelCount * 4, copyLength * pcm.ChannelCount * 4); + if (dataInFloat) + Buffer.BlockCopy(src.Float, srcOffset * pcm.ChannelCount * 4, Float, dstOffset * pcm.ChannelCount * 4, copyLength * pcm.ChannelCount * 4); + } + public unsafe void Prepare(AudioBuffer _src, int _offset, int _length) { length = Math.Min(size, _src.Length - _offset); @@ -365,19 +377,12 @@ namespace CUETools.Codecs dataInFloat = false; dataInSamples = false; if (_src.dataInBytes) - { dataInBytes = true; - fixed (byte* dest = Bytes, src = &_src.Bytes[_offset * pcm.BlockAlign]) - AudioSamples.MemCpy(dest, src, length * pcm.BlockAlign); - } else if (_src.dataInSamples) - { dataInSamples = true; - fixed (int* dest = Samples, src = &_src.Samples[_offset, 0]) - AudioSamples.MemCpy(dest, src, Length * pcm.ChannelCount); - } - else if (_src.dataInFloat) - throw new NotImplementedException(); + else if (_src.dataInFloat) + dataInFloat = true; + Load(0, _src, _offset, length); } public void Swap(AudioBuffer buffer) @@ -1731,6 +1736,10 @@ namespace CUETools.Codecs Process _encoderProcess; WAVWriter wrt; CyclicBuffer outputBuffer = null; + bool useTempFile = false; + string tempFile = null; + long _finalSampleCount = -1; + bool closed = false; public UserDefinedWriter(string path, Stream IO, AudioPCMConfig pcm, string encoder, string encoderParams, string encoderMode, int padding) { @@ -1738,15 +1747,23 @@ namespace CUETools.Codecs _encoder = encoder; _encoderParams = encoderParams; _encoderMode = encoderMode; + useTempFile = _encoderParams.Contains("%I"); + tempFile = path + ".tmp.wav"; _encoderProcess = new Process(); _encoderProcess.StartInfo.FileName = _encoder; - _encoderProcess.StartInfo.Arguments = _encoderParams.Replace("%O", "\"" + path + "\"").Replace("%M", encoderMode).Replace("%P", padding.ToString()); + _encoderProcess.StartInfo.Arguments = _encoderParams.Replace("%O", "\"" + path + "\"").Replace("%M", encoderMode).Replace("%P", padding.ToString()).Replace("%I", "\"" + tempFile + "\""); _encoderProcess.StartInfo.CreateNoWindow = true; - _encoderProcess.StartInfo.RedirectStandardInput = true; + if (!useTempFile) + _encoderProcess.StartInfo.RedirectStandardInput = true; _encoderProcess.StartInfo.UseShellExecute = false; if (!_encoderParams.Contains("%O")) _encoderProcess.StartInfo.RedirectStandardOutput = true; + if (useTempFile) + { + wrt = new WAVWriter(tempFile, null, pcm); + return; + } bool started = false; Exception ex = null; try @@ -1772,9 +1789,32 @@ namespace CUETools.Codecs public void Close() { + if (closed) + return; + closed = true; wrt.Close(); + if (useTempFile && (_finalSampleCount < 0 || wrt.Position == _finalSampleCount)) + { + bool started = false; + Exception ex = null; + try + { + started = _encoderProcess.Start(); + if (started) + _encoderProcess.PriorityClass = Process.GetCurrentProcess().PriorityClass; + } + catch (Exception _ex) + { + ex = _ex; + } + if (!started) + throw new Exception(_encoder + ": " + (ex == null ? "please check the path" : ex.Message)); + } + wrt = null; if (!_encoderProcess.HasExited) _encoderProcess.WaitForExit(); + if (useTempFile) + File.Delete(tempFile); if (outputBuffer != null) outputBuffer.Close(); if (_encoderProcess.ExitCode != 0) @@ -1797,7 +1837,7 @@ namespace CUETools.Codecs public long FinalSampleCount { - set { wrt.FinalSampleCount = value; } + set { _finalSampleCount = wrt.FinalSampleCount = value; } } public long BlockSize @@ -1948,6 +1988,7 @@ namespace CUETools.Codecs public class AudioPipe : IAudioSource//, IDisposable { private AudioBuffer _readBuffer, _writeBuffer; + private AudioPCMConfig pcm; long _sampleLen, _samplePos; private int _maxLength; private Thread _workThread; @@ -1959,14 +2000,22 @@ namespace CUETools.Codecs bool own; ThreadPriority priority; + public AudioPipe(AudioPCMConfig pcm, int size) + { + this.pcm = pcm; + _readBuffer = new AudioBuffer(pcm, size); + _writeBuffer = new AudioBuffer(pcm, size); + _maxLength = size; + _sampleLen = -1; + _samplePos = 0; + } + public AudioPipe(IAudioSource source, int size, bool own, ThreadPriority priority) + : this(source.PCM, size) { this.own = own; this.priority = priority; _source = source; - _readBuffer = new AudioBuffer(source, size); - _writeBuffer = new AudioBuffer(source, size); - _maxLength = size; _sampleLen = _source.Length; _samplePos = _source.Position; } @@ -2014,7 +2063,7 @@ namespace CUETools.Codecs private void Go() { - if (_workThread != null || _ex != null) return; + if (_workThread != null || _ex != null || _source == null) return; _workThread = new Thread(Decompress); _workThread.Priority = priority; _workThread.IsBackground = true; @@ -2067,6 +2116,9 @@ namespace CUETools.Codecs if (value == _samplePos) return; + if (_source == null) + throw new NotSupportedException(); + lock (this) { _close = true; @@ -2107,10 +2159,40 @@ namespace CUETools.Codecs { get { - return _source.PCM; + return pcm; } } + public int Write(AudioBuffer buff) + { + if (_writeBuffer.Size < _writeBuffer.Length + buff.Length) + { + AudioBuffer realloced = new AudioBuffer(pcm, _writeBuffer.Size + buff.Size); + realloced.Prepare(_writeBuffer, 0, _writeBuffer.Length); + _writeBuffer = realloced; + } + if (_writeBuffer.Length == 0) + _writeBuffer.Prepare(buff, 0, buff.Length); + else + { + _writeBuffer.Load(_writeBuffer.Length, buff, 0, buff.Length); + _writeBuffer.Length += buff.Length; + } + lock (this) + { + if (!_haveData) + { + AudioBuffer temp = _writeBuffer; + _writeBuffer = _readBuffer; + _writeBuffer.Length = 0; + _readBuffer = temp; + _haveData = true; + Monitor.Pulse(this); + } + } + return _writeBuffer.Length; + } + public int Read(AudioBuffer buff, int maxLength) { Go(); @@ -2152,7 +2234,15 @@ namespace CUETools.Codecs return buff.Length; } - public string Path { get { return _source.Path; } } + public string Path + { + get + { + if (_source == null) + return ""; + return _source.Path; + } + } } public class NullStream : Stream diff --git a/CUETools.DSP.Mixer/Mixer.cs b/CUETools.DSP.Mixer/Mixer.cs index 77acce1..02d5cf4 100644 --- a/CUETools.DSP.Mixer/Mixer.cs +++ b/CUETools.DSP.Mixer/Mixer.cs @@ -15,9 +15,14 @@ namespace CUETools.DSP.Mixer float[] volume; long samplePos; int size; + AudioReadEventArgs audioReadArgs = new AudioReadEventArgs(); + + public event EventHandler AudioRead; public MixingSource(AudioPCMConfig pcm, int delay, int sources) { + if (pcm.BitsPerSample != 32) + throw new NotSupportedException("please use 32 bits per sample (float)"); this.pcm = pcm; this.size = delay * pcm.SampleRate / 1000; this.buf = new MixingBuffer[2]; @@ -105,6 +110,14 @@ namespace CUETools.DSP.Mixer mixoffs = 0; } samplePos += result.Length; + + if (AudioRead != null) + { + audioReadArgs.source = this; + audioReadArgs.buffer = result; + AudioRead(this, audioReadArgs); + } + return result.Length; } @@ -331,7 +344,7 @@ namespace CUETools.DSP.Mixer } int chunk = Math.Min(buff.Length - buff_offs, mixbuff.source[iSource].Size - mixbuff.source[iSource].Length); - Buffer.BlockCopy(buff.Bytes, buff_offs * bs, mixbuff.source[iSource].Bytes, mixbuff.source[iSource].Length * bs, chunk * bs); + Buffer.BlockCopy(buff.Float, buff_offs * bs, mixbuff.source[iSource].Float, mixbuff.source[iSource].Length * bs, chunk * bs); mixbuff.source[iSource].Length += chunk; buff_offs += chunk; @@ -347,4 +360,10 @@ namespace CUETools.DSP.Mixer public string Path { get { return ""; } } } + + public class AudioReadEventArgs: EventArgs + { + public IAudioSource source; + public AudioBuffer buffer; + } } diff --git a/CUETools.Flake/Program.cs b/CUETools.Flake/Program.cs index fba04f2..3614543 100644 --- a/CUETools.Flake/Program.cs +++ b/CUETools.Flake/Program.cs @@ -45,7 +45,7 @@ namespace CUETools.FlakeExe Console.WriteLine(" -f #[,#] Prediction order {max} or {min},{max} (0..4)."); } - static void Main(string[] args) + static int Main(string[] args) { TextWriter stdout = Console.Out; Console.SetOut(Console.Error); @@ -143,13 +143,13 @@ namespace CUETools.FlakeExe if (!ok) { Usage(); - return; + return 1; } } if (input_file == null || ((input_file == "-" || Path.GetExtension(input_file) == ".flac") && output_file == null)) { Usage(); - return; + return 2; } if (!quiet) @@ -170,7 +170,7 @@ namespace CUETools.FlakeExe else { Usage(); - return; + return 3; } if (buffered) audioSource = new AudioPipe(audioSource, 0x10000); @@ -231,7 +231,7 @@ namespace CUETools.FlakeExe Usage(); Console.WriteLine(""); Console.WriteLine("Error: {0}.", ex.Message); - return; + return 4; } if (!quiet) @@ -240,25 +240,40 @@ namespace CUETools.FlakeExe Console.WriteLine("File Info : {0}kHz; {1} channel; {2} bit; {3}", audioSource.PCM.SampleRate, audioSource.PCM.ChannelCount, audioSource.PCM.BitsPerSample, TimeSpan.FromSeconds(audioSource.Length * 1.0 / audioSource.PCM.SampleRate)); } - while (audioSource.Read(buff, -1) != 0) +#if !DEBUG + try +#endif { - audioDest.Write(buff); - TimeSpan elapsed = DateTime.Now - start; - if (!quiet) + while (audioSource.Read(buff, -1) != 0) { - if ((elapsed - lastPrint).TotalMilliseconds > 60) + audioDest.Write(buff); + TimeSpan elapsed = DateTime.Now - start; + if (!quiet) { - Console.Error.Write("\rProgress : {0:00}%; {1:0.00}x; {2}/{3}", - 100.0 * audioSource.Position / audioSource.Length, - audioSource.Position / elapsed.TotalSeconds / audioSource.PCM.SampleRate, - elapsed, - TimeSpan.FromMilliseconds(elapsed.TotalMilliseconds / audioSource.Position * audioSource.Length) - ); - lastPrint = elapsed; + if ((elapsed - lastPrint).TotalMilliseconds > 60) + { + Console.Error.Write("\rProgress : {0:00}%; {1:0.00}x; {2}/{3}", + 100.0 * audioSource.Position / audioSource.Length, + audioSource.Position / elapsed.TotalSeconds / audioSource.PCM.SampleRate, + elapsed, + TimeSpan.FromMilliseconds(elapsed.TotalMilliseconds / audioSource.Position * audioSource.Length) + ); + lastPrint = elapsed; + } } } + audioDest.Close(); } - audioDest.Close(); +#if !DEBUG + catch (Exception ex) + { + Console.Error.Write("\r \r"); + Console.WriteLine("Error : {0}", ex.Message); + audioDest.Delete(); + audioSource.Close(); + return 5; + } +#endif TimeSpan totalElapsed = DateTime.Now - start; if (!quiet) @@ -293,6 +308,7 @@ namespace CUETools.FlakeExe flake.VBRMode ); } + return 0; } } } diff --git a/CUETools/CUETools.sln b/CUETools/CUETools.sln index 5b2e288..d594e28 100644 --- a/CUETools/CUETools.sln +++ b/CUETools/CUETools.sln @@ -167,6 +167,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CUETools.DSP.Mixer", "..\CU EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CUETools.DSP.Resampler", "..\CUETools.DSP.Resampler\CUETools.DSP.Resampler.csproj", "{A6303861-CA06-4C2C-A104-BA9291538F6F}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CUETools.Codecs.Icecast", "..\CUETools.Codecs.Icecast\CUETools.Codecs.Icecast.csproj", "{8FC5DA7C-F6AC-4D04-85BC-1233DDF569E7}" +EndProject Global GlobalSection(TestCaseManagementSettings) = postSolution CategoryFile = CUETools1.vsmdi @@ -630,6 +632,14 @@ Global {A6303861-CA06-4C2C-A104-BA9291538F6F}.Release|Any CPU.Build.0 = Release|Any CPU {A6303861-CA06-4C2C-A104-BA9291538F6F}.Release|Win32.ActiveCfg = Release|Any CPU {A6303861-CA06-4C2C-A104-BA9291538F6F}.Release|x64.ActiveCfg = Release|Any CPU + {8FC5DA7C-F6AC-4D04-85BC-1233DDF569E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8FC5DA7C-F6AC-4D04-85BC-1233DDF569E7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8FC5DA7C-F6AC-4D04-85BC-1233DDF569E7}.Debug|Win32.ActiveCfg = Debug|Any CPU + {8FC5DA7C-F6AC-4D04-85BC-1233DDF569E7}.Debug|x64.ActiveCfg = Debug|Any CPU + {8FC5DA7C-F6AC-4D04-85BC-1233DDF569E7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8FC5DA7C-F6AC-4D04-85BC-1233DDF569E7}.Release|Any CPU.Build.0 = Release|Any CPU + {8FC5DA7C-F6AC-4D04-85BC-1233DDF569E7}.Release|Win32.ActiveCfg = Release|Any CPU + {8FC5DA7C-F6AC-4D04-85BC-1233DDF569E7}.Release|x64.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE