Improved design and made the changes to tone characteristics update on next change.

This commit is contained in:
Mark Hamann 2016-02-26 08:08:53 -08:00
parent e778b1d1b6
commit 8ad36377f2
3 changed files with 125 additions and 48 deletions

View file

@ -119,8 +119,9 @@ namespace MorseTrainer
_runner.StopDelayEnter += _runner_StopDelayEnter; _runner.StopDelayEnter += _runner_StopDelayEnter;
_runner.StopDelayExit += _runner_StopDelayExit; _runner.StopDelayExit += _runner_StopDelayExit;
_runner.Abort += _runner_Abort; _runner.Abort += _runner_Abort;
_player.QueueEmpty += _player_QueueEmpty; _player.Dequeued += _player_Dequeued;
_player.PlayingFinished += _player_PlayingFinished; _player.PlayingFinished += _player_PlayingFinished;
_toneGenerator.UpdateRequired += _toneGenerator_UpdateRequired;
cmbKoch.Items.Clear(); cmbKoch.Items.Clear();
for (int i = 0; i < Koch.Length; ++i) for (int i = 0; i < Koch.Length; ++i)
@ -216,8 +217,7 @@ namespace MorseTrainer
{ {
if (_runner.IsRunning) if (_runner.IsRunning)
{ {
_pendingWavestream = null; _player.ClearQueue();
_player.Clear();
btnStartStop.Enabled = false; btnStartStop.Enabled = false;
_runner.RequestStop(); _runner.RequestStop();
} }
@ -234,13 +234,18 @@ namespace MorseTrainer
private void FirstWaveReadyCallback(IAsyncResult result) private void FirstWaveReadyCallback(IAsyncResult result)
{ {
_pendingWavestream = (WaveStream)result.AsyncState; WaveStream waveStream = (WaveStream)result.AsyncState;
_player.Enqueue(waveStream);
_runner.RequestStart(); _runner.RequestStart();
} }
private void WaveReadyCallback(IAsyncResult result) private void WaveReadyCallback(IAsyncResult result)
{ {
_pendingWavestream = (WaveStream)result.AsyncState; WaveStream waveStream = (WaveStream)result.AsyncState;
if (waveStream != null)
{
_player.Enqueue(waveStream);
}
} }
private void _runner_StartDelayEnter(object sender, EventArgs e) private void _runner_StartDelayEnter(object sender, EventArgs e)
@ -253,21 +258,28 @@ namespace MorseTrainer
private void _runner_MorseEnter(object sender, EventArgs e) private void _runner_MorseEnter(object sender, EventArgs e)
{ {
_player.Start(_pendingWavestream); _player.Start();
_pendingWavestream = null;
String word = _charGenerator.CreateRandomString(); String word = _charGenerator.CreateRandomString();
_builder.StartBuildAsync(word, new AsyncCallback(WaveReadyCallback)); _builder.StartBuildAsync(word, new AsyncCallback(WaveReadyCallback));
} }
private void _player_QueueEmpty(object sender, EventArgs e) private void _player_Dequeued(object sender, EventArgs e)
{ {
if (_runner.ContinueMorse) if (_runner.ContinueMorse)
{ {
_player.Enqueue(_pendingWavestream);
_builder.StartBuildAsync(_charGenerator.CreateRandomString(), new AsyncCallback(WaveReadyCallback)); _builder.StartBuildAsync(_charGenerator.CreateRandomString(), new AsyncCallback(WaveReadyCallback));
} }
} }
private void _toneGenerator_UpdateRequired(object sender, EventArgs e)
{
// This indicates that the tone has changed. If we are currently sending code,
// we need to remove any queued tones and in progress tones and send new tones instead
_toneGenerator.Update();
_player.ClearQueue();
_builder.StartBuildAsync(_charGenerator.CreateRandomString(), new AsyncCallback(WaveReadyCallback));
}
private void _player_PlayingFinished(object sender, EventArgs e) private void _player_PlayingFinished(object sender, EventArgs e)
{ {
_runner.AcknowledgeSendEnd(); _runner.AcknowledgeSendEnd();
@ -275,6 +287,8 @@ namespace MorseTrainer
private void _runner_MorseExit(object sender, EventArgs e) private void _runner_MorseExit(object sender, EventArgs e)
{ {
_player.Stop();
_player.ClearQueue();
} }
private void _runner_StopDelayEnter(object sender, EventArgs e) private void _runner_StopDelayEnter(object sender, EventArgs e)
@ -1251,7 +1265,6 @@ namespace MorseTrainer
private Runner _runner; private Runner _runner;
private Analyzer _analyzer; private Analyzer _analyzer;
private StringBuilder _recorded; private StringBuilder _recorded;
private WaveStream _pendingWavestream;
#endregion #endregion
} }

View file

@ -36,6 +36,7 @@ namespace MorseTrainer
/// </summary> /// </summary>
public SoundPlayerAsync() public SoundPlayerAsync()
{ {
_sending = false;
_mediaSoundPlayer = new System.Media.SoundPlayer(); _mediaSoundPlayer = new System.Media.SoundPlayer();
_queue = new Queue<WaveStream>(); _queue = new Queue<WaveStream>();
_sentString = new StringBuilder(); _sentString = new StringBuilder();
@ -49,6 +50,17 @@ namespace MorseTrainer
private void ThreadMain() private void ThreadMain()
{ {
while (!_stopThread) while (!_stopThread)
{
bool go = false;
lock (this)
{
if (!_sending)
{
System.Threading.Monitor.Wait(this);
}
go = _sending && !_stopThread;
}
if (go)
{ {
WaveStream waveToPlay = Dequeue(); WaveStream waveToPlay = Dequeue();
if (waveToPlay != null) if (waveToPlay != null)
@ -65,9 +77,10 @@ namespace MorseTrainer
} }
} }
} }
}
lock(this) lock(this)
{ {
_stopped = true; _threadStopped = true;
System.Threading.Monitor.Pulse(this); System.Threading.Monitor.Pulse(this);
} }
} }
@ -86,7 +99,7 @@ namespace MorseTrainer
wave = _queue.Dequeue(); wave = _queue.Dequeue();
if (_queue.Count == 0) if (_queue.Count == 0)
{ {
OnQueueEmpty(); OnDequeued();
} }
} }
} }
@ -96,12 +109,22 @@ namespace MorseTrainer
/// <summary> /// <summary>
/// Puts a WAV onto the queue and resets the strings /// Puts a WAV onto the queue and resets the strings
/// </summary> /// </summary>
/// <param name="wave">A WaveStream</param> public void Start()
public void Start(WaveStream wave)
{ {
Enqueue(wave); lock(this)
{
_sending = true;
_sentString.Clear(); _sentString.Clear();
} }
}
public void Stop()
{
lock(this)
{
_sending = false;
}
}
/// <summary> /// <summary>
/// Gets the words sent /// Gets the words sent
@ -129,9 +152,9 @@ namespace MorseTrainer
} }
/// <summary> /// <summary>
/// Clear all waves from the queue when aborting /// ClearQueue all waves from the queue when aborting
/// </summary> /// </summary>
public void Clear() public void ClearQueue()
{ {
lock(this) lock(this)
{ {
@ -168,12 +191,12 @@ namespace MorseTrainer
} }
/// <summary> /// <summary>
/// The queue has been emptied. Action in this should be quick /// The queue has been dequeued. Action in this should be quick
/// </summary> /// </summary>
public event EventHandler QueueEmpty; public event EventHandler Dequeued;
protected void OnQueueEmpty() protected void OnDequeued()
{ {
EventHandler handler = QueueEmpty; EventHandler handler = Dequeued;
if (handler != null) if (handler != null)
{ {
handler(this, EventArgs.Empty); handler(this, EventArgs.Empty);
@ -190,10 +213,10 @@ namespace MorseTrainer
if (_thread != null && !_stopThread) if (_thread != null && !_stopThread)
{ {
_stopThread = true; _stopThread = true;
_stopped = false; _threadStopped = false;
_queue.Clear(); _queue.Clear();
System.Threading.Monitor.Pulse(this); System.Threading.Monitor.Pulse(this);
if (!_stopped) if (!_threadStopped)
{ {
System.Threading.Monitor.Wait(this); System.Threading.Monitor.Wait(this);
} }
@ -206,7 +229,9 @@ namespace MorseTrainer
private System.Threading.Thread _thread; private System.Threading.Thread _thread;
private bool _stopThread; private bool _stopThread;
private bool _stopped; private bool _threadStopped;
private bool _sending;
private Queue<WaveStream> _queue; private Queue<WaveStream> _queue;
private System.Media.SoundPlayer _mediaSoundPlayer; private System.Media.SoundPlayer _mediaSoundPlayer;
private StringBuilder _sentString; private StringBuilder _sentString;

View file

@ -85,6 +85,7 @@ namespace MorseTrainer
_WPM = 0; _WPM = 0;
_farnsworthWPM = 0; _farnsworthWPM = 0;
_volume = 0.0f; _volume = 0.0f;
_updateRequired = true;
} }
private float WpmToMillesecPerElement(float wpm) private float WpmToMillesecPerElement(float wpm)
@ -102,6 +103,10 @@ namespace MorseTrainer
/// </summary> /// </summary>
public void Update() public void Update()
{ {
if (_updateRequired)
{
_updateRequired = false;
// changing tone frequency or WPM will cause the tones to be regenerated // changing tone frequency or WPM will cause the tones to be regenerated
if (_frequency == 0 || _frequency != _newFrequency || _newWPM != _WPM || _newVolume != _volume) if (_frequency == 0 || _frequency != _newFrequency || _newWPM != _WPM || _newVolume != _volume)
{ {
@ -122,6 +127,35 @@ namespace MorseTrainer
_msPerFarnsworthElement = WpmToMillesecPerElement(_farnsworthWPM); _msPerFarnsworthElement = WpmToMillesecPerElement(_farnsworthWPM);
} }
} }
}
/// <summary>
/// The user has made a change that will require an update
/// </summary>
public event EventHandler UpdateRequired;
protected void OnUpdateRequired()
{
if (!_updateRequired)
{
_updateRequired = true;
EventHandler handler = UpdateRequired;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
/// <summary>
/// Gets if there is a required update to generated tones
/// </summary>
public bool IsUpdateRequired
{
get
{
return _updateRequired;
}
}
/// <summary> /// <summary>
/// Gets the current frequency in Hertz /// Gets the current frequency in Hertz
@ -150,6 +184,7 @@ namespace MorseTrainer
throw new ArgumentOutOfRangeException("Frequency"); throw new ArgumentOutOfRangeException("Frequency");
} }
_newFrequency = value; _newFrequency = value;
OnUpdateRequired();
} }
} }
@ -169,6 +204,7 @@ namespace MorseTrainer
throw new ArgumentOutOfRangeException("Volume"); throw new ArgumentOutOfRangeException("Volume");
} }
_newVolume = value; _newVolume = value;
OnUpdateRequired();
} }
} }
@ -199,6 +235,7 @@ namespace MorseTrainer
throw new ArgumentOutOfRangeException("WPM"); throw new ArgumentOutOfRangeException("WPM");
} }
_newWPM = (float)Math.Round(value * 2) / 2; _newWPM = (float)Math.Round(value * 2) / 2;
OnUpdateRequired();
} }
} }
@ -229,6 +266,7 @@ namespace MorseTrainer
throw new ArgumentOutOfRangeException("WPM"); throw new ArgumentOutOfRangeException("WPM");
} }
_newFarnsworthWPM = (float)Math.Round(value * 2) / 2; _newFarnsworthWPM = (float)Math.Round(value * 2) / 2;
OnUpdateRequired();
} }
} }
@ -382,6 +420,7 @@ namespace MorseTrainer
return CreateSpace(difference); return CreateSpace(difference);
} }
private bool _updateRequired;
private UInt16 _frequency; private UInt16 _frequency;
private UInt16 _newFrequency; private UInt16 _newFrequency;
private float _WPM; private float _WPM;