mirror of https://github.com/naudio/NAudio.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
612 lines
20 KiB
612 lines
20 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Data;
|
|
using System.Drawing;
|
|
using System.Text;
|
|
using System.Windows.Forms;
|
|
using System.Xml;
|
|
using NAudio.Wave;
|
|
using MarkHeath.AudioUtils.Properties;
|
|
|
|
namespace MarkHeath.AudioUtils
|
|
{
|
|
public partial class MixDiffForm : Form
|
|
{
|
|
private PlaybackStatus playbackStatus;
|
|
private IWavePlayer wavePlayer;
|
|
readonly Font BigFont = new Font("Verdana", 36, FontStyle.Bold);
|
|
readonly Font EmptyFont = new Font("Verdana", 16, FontStyle.Bold);
|
|
private WaveMixerStream32 mixer;
|
|
private int skipSeconds;
|
|
private Button selectedButton;
|
|
private CompareMode compareMode;
|
|
private List<Button> fileButtons;
|
|
private bool shuffled;
|
|
|
|
public MixDiffForm()
|
|
{
|
|
InitializeComponent();
|
|
mixer = new WaveMixerStream32();
|
|
mixer.AutoStop = false;
|
|
skipSeconds = 3;
|
|
fileButtons = new List<Button>();
|
|
fileButtons.Add(buttonA);
|
|
fileButtons.Add(buttonB);
|
|
fileButtons.Add(buttonC);
|
|
fileButtons.Add(buttonD);
|
|
|
|
}
|
|
|
|
|
|
private bool LoadFile(Button button)
|
|
{
|
|
// prompt for file load
|
|
OpenFileDialog openFileDialog = new OpenFileDialog();
|
|
openFileDialog.Filter = "WAV Files (*.wav)|*.wav";
|
|
if (openFileDialog.ShowDialog() == DialogResult.OK)
|
|
{
|
|
MixdownInfo info = new MixdownInfo(openFileDialog.FileName);
|
|
// TODO: sort this out - post shuffle
|
|
info.Letter = button.Name.Substring(button.Name.Length - 1);
|
|
SetButtonInfo(button, info);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private void SetButtonInfo(Button button, MixdownInfo info)
|
|
{
|
|
if (button.Tag != null)
|
|
{
|
|
ClearFile(button);
|
|
}
|
|
button.Tag = info;
|
|
SetButtonAppearance(button);
|
|
mixer.AddInputStream(info.Stream);
|
|
SetLengthLabel();
|
|
}
|
|
|
|
private void ClearFile(Button button)
|
|
{
|
|
if (button.Tag != null)
|
|
{
|
|
MixdownInfo buttonInfo = button.Tag as MixdownInfo;
|
|
mixer.RemoveInputStream(buttonInfo.Stream);
|
|
buttonInfo.Stream.Close();
|
|
button.Tag = null;
|
|
SetButtonAppearance(button);
|
|
}
|
|
}
|
|
|
|
private void SetButtonAppearance(Button button)
|
|
{
|
|
MixdownInfo info = button.Tag as MixdownInfo;
|
|
if (info == null)
|
|
{
|
|
button.Text = "<Empty>";
|
|
button.Font = EmptyFont;
|
|
toolTip1.SetToolTip(button, null);
|
|
}
|
|
else
|
|
{
|
|
if (shuffled)
|
|
{
|
|
button.Text = "?";
|
|
toolTip1.SetToolTip(button, null);
|
|
button.Font = BigFont;
|
|
}
|
|
else
|
|
{
|
|
button.Text = info.Letter;
|
|
toolTip1.SetToolTip(button, info.FileName);
|
|
button.Font = BigFont;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void OnMixButtonClick(object sender, EventArgs e)
|
|
{
|
|
Button button = sender as Button;
|
|
if (button.Tag == null)
|
|
{
|
|
if (LoadFile(button))
|
|
{
|
|
SelectButton(button);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SelectButton(button);
|
|
}
|
|
}
|
|
|
|
private void SelectButton(Button button)
|
|
{
|
|
MixdownInfo info;
|
|
if (selectedButton != null)
|
|
{
|
|
selectedButton.BackColor = SystemColors.Control;
|
|
selectedButton.ForeColor = SystemColors.ControlText;
|
|
info = selectedButton.Tag as MixdownInfo;
|
|
if (info != null)
|
|
{
|
|
// can be null if active button is cleared
|
|
info.Stream.Mute = true;
|
|
}
|
|
}
|
|
info = button.Tag as MixdownInfo;
|
|
button.ForeColor = Color.DarkGreen;
|
|
button.BackColor = Color.LightGoldenrodYellow;
|
|
info.Stream.Mute = false;
|
|
selectedButton = button;
|
|
if (playbackStatus == PlaybackStatus.Playing)
|
|
{
|
|
if (compareMode == CompareMode.SkipBack)
|
|
{
|
|
SkipBack();
|
|
}
|
|
else if (compareMode == CompareMode.Restart)
|
|
{
|
|
Rewind();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void Play()
|
|
{
|
|
if (playbackStatus != PlaybackStatus.Playing)
|
|
{
|
|
if (playbackStatus != PlaybackStatus.Paused)
|
|
{
|
|
Rewind();
|
|
}
|
|
if (wavePlayer == null)
|
|
{
|
|
wavePlayer = new WaveOut();
|
|
wavePlayer.Init(mixer);
|
|
}
|
|
wavePlayer.Play();
|
|
playbackStatus = PlaybackStatus.Playing;
|
|
timer1.Start();
|
|
}
|
|
}
|
|
|
|
private void Stop()
|
|
{
|
|
if (playbackStatus != PlaybackStatus.Stopped)
|
|
{
|
|
if (wavePlayer != null)
|
|
{
|
|
wavePlayer.Stop();
|
|
playbackStatus = PlaybackStatus.Stopped;
|
|
timer1.Stop();
|
|
}
|
|
Rewind();
|
|
}
|
|
}
|
|
|
|
private void Pause()
|
|
{
|
|
if (playbackStatus == PlaybackStatus.Playing)
|
|
{
|
|
wavePlayer.Pause();
|
|
playbackStatus = PlaybackStatus.Paused;
|
|
}
|
|
}
|
|
|
|
private void toolStripButtonPlay_Click(object sender, EventArgs e)
|
|
{
|
|
Play();
|
|
}
|
|
|
|
private void timer1_Tick(object sender, EventArgs e)
|
|
{
|
|
if (playbackStatus == PlaybackStatus.Playing)
|
|
{
|
|
if (mixer.Position > mixer.Length)
|
|
{
|
|
if (toolStripButtonLoop.Checked)
|
|
{
|
|
Rewind();
|
|
}
|
|
else
|
|
{
|
|
Stop();
|
|
}
|
|
}
|
|
|
|
SetPositionLabel();
|
|
}
|
|
}
|
|
|
|
private void SetPositionLabel()
|
|
{
|
|
TimeSpan currentTime = mixer.CurrentTime;
|
|
toolStripLabelPosition.Text = String.Format("{0:00}:{1:00}:{2:00}.{3:000}",
|
|
currentTime.Hours,
|
|
currentTime.Minutes,
|
|
currentTime.Seconds,
|
|
currentTime.Milliseconds);
|
|
}
|
|
|
|
private void SetLengthLabel()
|
|
{
|
|
TimeSpan length = mixer.TotalTime;
|
|
toolStripLabelLength.Text = String.Format("{0:00}:{1:00}:{2:00}",
|
|
length.Hours,
|
|
length.Minutes,
|
|
length.Seconds);
|
|
|
|
}
|
|
|
|
private void MixDiffForm_FormClosing(object sender, FormClosingEventArgs e)
|
|
{
|
|
if (playbackStatus != PlaybackStatus.Stopped)
|
|
{
|
|
Stop();
|
|
}
|
|
if (wavePlayer != null)
|
|
{
|
|
wavePlayer.Dispose();
|
|
wavePlayer = null;
|
|
}
|
|
if (mixer != null)
|
|
{
|
|
mixer.Dispose();
|
|
mixer = null;
|
|
}
|
|
}
|
|
|
|
private void toolStripButtonStop_Click(object sender, EventArgs e)
|
|
{
|
|
Stop();
|
|
}
|
|
|
|
private void toolStripButtonPause_Click(object sender, EventArgs e)
|
|
{
|
|
Pause();
|
|
}
|
|
|
|
private void toolStripButtonBack_Click(object sender, EventArgs e)
|
|
{
|
|
SkipBack();
|
|
}
|
|
|
|
private void toolStripButtonForward_Click(object sender, EventArgs e)
|
|
{
|
|
if (mixer != null)
|
|
{
|
|
mixer.CurrentTime += TimeSpan.FromSeconds(skipSeconds);
|
|
SetPositionLabel();
|
|
|
|
}
|
|
}
|
|
|
|
private void toolStripButtonRewind_Click(object sender, EventArgs e)
|
|
{
|
|
Rewind();
|
|
}
|
|
|
|
private void SkipBack()
|
|
{
|
|
if (mixer != null)
|
|
{
|
|
mixer.CurrentTime += TimeSpan.FromSeconds(0 - skipSeconds);
|
|
SetPositionLabel();
|
|
}
|
|
}
|
|
|
|
private void Rewind()
|
|
{
|
|
if (mixer != null)
|
|
{
|
|
mixer.Position = 0;
|
|
SetPositionLabel();
|
|
}
|
|
}
|
|
|
|
public CompareMode CompareMode
|
|
{
|
|
get { return compareMode; }
|
|
set
|
|
{
|
|
compareMode = value;
|
|
currentPositionToolStripMenuItem1.Checked = (compareMode == CompareMode.CurrentPosition);
|
|
skipBackToolStripMenuItem1.Checked = (compareMode == CompareMode.SkipBack);
|
|
restartToolStripMenuItem1.Checked = (compareMode == CompareMode.Restart);
|
|
}
|
|
|
|
}
|
|
|
|
private void currentPositionToolStripMenuItem1_Click(object sender, EventArgs e)
|
|
{
|
|
CompareMode = CompareMode.CurrentPosition;
|
|
}
|
|
|
|
private void skipBackToolStripMenuItem1_Click(object sender, EventArgs e)
|
|
{
|
|
CompareMode = CompareMode.SkipBack;
|
|
}
|
|
|
|
private void restartToolStripMenuItem1_Click(object sender, EventArgs e)
|
|
{
|
|
CompareMode = CompareMode.Restart;
|
|
}
|
|
|
|
private void exitToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
this.Close();
|
|
}
|
|
|
|
private void clearToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
Button button = (Button)contextMenuStrip1.SourceControl;
|
|
ClearFile(button);
|
|
}
|
|
|
|
private void selectFileToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
Button button = (Button)contextMenuStrip1.SourceControl;
|
|
LoadFile(button);
|
|
}
|
|
|
|
private void propertiesToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
Button button = (Button)contextMenuStrip1.SourceControl;
|
|
if (button.Tag != null)
|
|
{
|
|
MixdownInfo mixdownInfo = button.Tag as MixdownInfo;
|
|
PropertiesForm propertiesForm = new PropertiesForm(mixdownInfo);
|
|
if (propertiesForm.ShowDialog() == DialogResult.OK)
|
|
{
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
private void saveComparisonToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
SaveFileDialog saveFileDialog = new SaveFileDialog();
|
|
saveFileDialog.DefaultExt = ".MixDiff";
|
|
saveFileDialog.Filter = "*.MixDiff (MixDiff Comparison Files)|*.MixDiff|*.* (All Files)|*.*";
|
|
if (saveFileDialog.ShowDialog() == DialogResult.OK)
|
|
{
|
|
SaveComparison(saveFileDialog.FileName);
|
|
}
|
|
}
|
|
|
|
private void SaveComparison(string fileName)
|
|
{
|
|
XmlWriterSettings settings = new XmlWriterSettings();
|
|
settings.Indent = true;
|
|
settings.NewLineOnAttributes = true;
|
|
|
|
using (XmlWriter writer = XmlWriter.Create(fileName,settings))
|
|
{
|
|
writer.WriteStartElement("MixDiff");
|
|
writer.WriteStartElement("Settings");
|
|
writer.WriteAttributeString("CompareMode", compareMode.ToString());
|
|
writer.WriteEndElement();
|
|
foreach (Button button in fileButtons)
|
|
{
|
|
WriteMixdownInfo(writer, button.Tag as MixdownInfo);
|
|
}
|
|
writer.WriteEndElement();
|
|
}
|
|
}
|
|
|
|
private void LoadComparison(string fileName)
|
|
{
|
|
XmlDocument document = new XmlDocument();
|
|
document.Load(fileName);
|
|
XmlNode compareModeNode = document.SelectSingleNode("MixDiff/Settings/@CompareMode");
|
|
CompareMode = (CompareMode)Enum.Parse(typeof(CompareMode), compareModeNode.Value);
|
|
XmlNodeList mixes = document.SelectNodes("MixDiff/Mix");
|
|
int buttonIndex = 0;
|
|
foreach(XmlNode mixNode in mixes)
|
|
{
|
|
Button button = fileButtons[buttonIndex++];
|
|
MixdownInfo info = new MixdownInfo(mixNode.SelectSingleNode("@FileName").Value);
|
|
info.DelayMilliseconds = Int32.Parse(mixNode.SelectSingleNode("@DelayMilliseconds").Value);
|
|
info.OffsetMilliseconds = Int32.Parse(mixNode.SelectSingleNode("@OffsetMilliseconds").Value);
|
|
info.VolumeDecibels = Int32.Parse(mixNode.SelectSingleNode("@VolumeDecibels").Value);
|
|
info.Letter = button.Name.Substring(button.Name.Length - 1);
|
|
info.Stream.Mute = true;
|
|
SetButtonInfo(button,info);
|
|
}
|
|
SelectButton(fileButtons[0]);
|
|
}
|
|
|
|
private void WriteMixdownInfo(XmlWriter writer, MixdownInfo mixdownInfo)
|
|
{
|
|
if (mixdownInfo != null)
|
|
{
|
|
writer.WriteStartElement("Mix");
|
|
writer.WriteAttributeString("FileName", mixdownInfo.FileName);
|
|
writer.WriteAttributeString("DelayMilliseconds", mixdownInfo.DelayMilliseconds.ToString());
|
|
writer.WriteAttributeString("OffsetMilliseconds", mixdownInfo.OffsetMilliseconds.ToString());
|
|
writer.WriteAttributeString("VolumeDecibels", mixdownInfo.VolumeDecibels.ToString());
|
|
writer.WriteEndElement();
|
|
}
|
|
}
|
|
|
|
private void openSavedComparisonToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
OpenFileDialog openFileDialog = new OpenFileDialog();
|
|
openFileDialog.DefaultExt = ".MixDiff";
|
|
openFileDialog.Filter = "*.MixDiff (MixDiff Comparison Files)|*.MixDiff|*.* (All Files)|*.*";
|
|
if (openFileDialog.ShowDialog() == DialogResult.OK)
|
|
{
|
|
Stop();
|
|
foreach(Button button in fileButtons)
|
|
{
|
|
ClearFile(button);
|
|
}
|
|
LoadComparison(openFileDialog.FileName);
|
|
}
|
|
}
|
|
|
|
private void contentsToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
try
|
|
{
|
|
System.Diagnostics.Process.Start("http://www.codeplex.com/naudio/Wiki/View.aspx?title=MixDiff");
|
|
}
|
|
catch (Exception)
|
|
{
|
|
MessageBox.Show("Failed to launch browser to show help file");
|
|
}
|
|
|
|
}
|
|
|
|
private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
NAudio.Utils.AboutForm aboutForm = new NAudio.Utils.AboutForm();
|
|
aboutForm.ShowDialog();
|
|
}
|
|
|
|
private void settingsToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
SettingsForm settingsForm = new SettingsForm();
|
|
if (settingsForm.ShowDialog() == DialogResult.OK)
|
|
{
|
|
// TODO: reopen WaveOut device
|
|
}
|
|
|
|
}
|
|
|
|
private void toolStripButtonShuffle_Click(object sender, EventArgs e)
|
|
{
|
|
if (!shuffled)
|
|
{
|
|
Shuffle();
|
|
}
|
|
else
|
|
{
|
|
Reveal();
|
|
}
|
|
|
|
toolStripButtonShuffle.Checked = shuffled;
|
|
}
|
|
|
|
private void Shuffle()
|
|
{
|
|
List<MixdownInfo> mixdowns = new List<MixdownInfo>();
|
|
foreach (Button button in fileButtons)
|
|
{
|
|
if (button.Tag != null)
|
|
{
|
|
mixdowns.Add(button.Tag as MixdownInfo);
|
|
}
|
|
}
|
|
|
|
|
|
Random rand = new Random();
|
|
if (mixdowns.Count < 2)
|
|
{
|
|
MessageBox.Show("You need to have at least two files to compare to use the shuffle feature",
|
|
Application.ProductName);
|
|
return;
|
|
}
|
|
|
|
shuffled = true;
|
|
|
|
if (Settings.Default.UseAllSlots)
|
|
{
|
|
foreach (Button button in fileButtons)
|
|
{
|
|
if (button.Tag == null)
|
|
{
|
|
button.Tag = mixdowns[rand.Next() % mixdowns.Count];
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int n = 0; n < 12; n++)
|
|
{
|
|
int swap1 = rand.Next() % fileButtons.Count;
|
|
int swap2 = rand.Next() % fileButtons.Count;
|
|
if (swap1 != swap2)
|
|
{
|
|
object tag1 = fileButtons[swap1].Tag;
|
|
fileButtons[swap1].Tag = fileButtons[swap2].Tag;
|
|
fileButtons[swap2].Tag = tag1;
|
|
}
|
|
}
|
|
|
|
Button firstMix = null;
|
|
foreach (Button button in fileButtons)
|
|
{
|
|
SetButtonAppearance(button);
|
|
if (button.Tag != null && firstMix == null)
|
|
firstMix = button;
|
|
}
|
|
SelectButton(firstMix);
|
|
}
|
|
|
|
private void Reveal()
|
|
{
|
|
shuffled = false;
|
|
foreach (Button button in fileButtons)
|
|
{
|
|
SetButtonAppearance(button);
|
|
}
|
|
}
|
|
|
|
private void MixDiffForm_KeyDown(object sender, KeyEventArgs e)
|
|
{
|
|
switch (e.KeyCode)
|
|
{
|
|
case Keys.D1:
|
|
OnMixButtonClick(buttonA, EventArgs.Empty);
|
|
e.Handled = true;
|
|
break;
|
|
case Keys.D2:
|
|
OnMixButtonClick(buttonB, EventArgs.Empty);
|
|
e.Handled = true;
|
|
break;
|
|
case Keys.D3:
|
|
OnMixButtonClick(buttonC, EventArgs.Empty);
|
|
e.Handled = true;
|
|
break;
|
|
case Keys.D4:
|
|
OnMixButtonClick(buttonD, EventArgs.Empty);
|
|
e.Handled = true;
|
|
break;
|
|
case Keys.Space:
|
|
if (playbackStatus != PlaybackStatus.Playing)
|
|
{
|
|
Play();
|
|
}
|
|
else
|
|
{
|
|
Pause();
|
|
}
|
|
e.Handled = true;
|
|
break;
|
|
case Keys.Home:
|
|
Rewind();
|
|
e.Handled = true;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
public enum CompareMode
|
|
{
|
|
CurrentPosition,
|
|
SkipBack,
|
|
Restart,
|
|
}
|
|
|
|
enum PlaybackStatus
|
|
{
|
|
Stopped,
|
|
Playing,
|
|
Paused
|
|
}
|
|
}
|