From c22634ac7a1ec970a27e9c33bb776d6530c77332 Mon Sep 17 00:00:00 2001 From: Michael Paul Coder Date: Mon, 15 Aug 2022 07:31:00 +1000 Subject: [PATCH] Smooth out sine waves with portamenti --- Halovision/DataChunk.cs | 56 -------- Halovision/FifoStream.cs | 168 ----------------------- Halovision/FormatChunk.cs | 77 ----------- Halovision/Halovision.csproj | 6 +- Halovision/PluginHandler.cs | 47 ++++--- Halovision/Properties/AssemblyInfo.cs | 4 +- Halovision/SignalGenerator.cs | 138 ------------------- Halovision/SineGenerator.cs | 37 ----- Halovision/SineWaveProvider.cs | 75 ++++++++++ Installer/Lucid Scribe Halovision.vdproj | 6 +- 10 files changed, 110 insertions(+), 504 deletions(-) delete mode 100644 Halovision/DataChunk.cs delete mode 100644 Halovision/FifoStream.cs delete mode 100644 Halovision/FormatChunk.cs delete mode 100644 Halovision/SignalGenerator.cs delete mode 100644 Halovision/SineGenerator.cs create mode 100644 Halovision/SineWaveProvider.cs diff --git a/Halovision/DataChunk.cs b/Halovision/DataChunk.cs deleted file mode 100644 index 41aa828..0000000 --- a/Halovision/DataChunk.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace lucidcode.LucidScribe.Plugin.Halovision -{ - internal class DataChunk - { - private const string CHUNK_ID = "data"; - - public string ChunkId { get; private set; } - public UInt32 ChunkSize { get; set; } - public short[] WaveData { get; private set; } - - public DataChunk() - { - ChunkId = CHUNK_ID; - ChunkSize = 0; - } - - public UInt32 Length() - { - return (UInt32)GetBytes().Length; - } - - public byte[] GetBytes() - { - List chunkBytes = new List(); - - chunkBytes.AddRange(Encoding.ASCII.GetBytes(ChunkId)); - chunkBytes.AddRange(BitConverter.GetBytes(ChunkSize)); - byte[] bufferBytes = new byte[WaveData.Length * 2]; - Buffer.BlockCopy(WaveData, 0, bufferBytes, 0, - bufferBytes.Length); - chunkBytes.AddRange(bufferBytes.ToList()); - - return chunkBytes.ToArray(); - } - - public void AddSampleData(short[] leftBuffer, - short[] rightBuffer) - { - WaveData = new short[leftBuffer.Length + - rightBuffer.Length]; - int bufferOffset = 0; - for (int index = 0; index < WaveData.Length; index += 2) - { - WaveData[index] = leftBuffer[bufferOffset]; - WaveData[index + 1] = rightBuffer[bufferOffset]; - bufferOffset++; - } - ChunkSize = (UInt32)WaveData.Length * 2; - } - } -} diff --git a/Halovision/FifoStream.cs b/Halovision/FifoStream.cs deleted file mode 100644 index 7a32595..0000000 --- a/Halovision/FifoStream.cs +++ /dev/null @@ -1,168 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using System.Collections; - -namespace lucidcode.LucidScribe.Plugin.Halovision -{ - public class FifoStream : Stream - { - private const int BlockSize = 65536; - private const int MaxBlocksInCache = (3 * 1024 * 1024) / BlockSize; - - private int m_Size; - private int m_RPos; - private int m_WPos; - private Stack m_UsedBlocks = new Stack(); - private ArrayList m_Blocks = new ArrayList(); - - private byte[] AllocBlock() - { - byte[] Result = null; - Result = m_UsedBlocks.Count > 0 ? (byte[])m_UsedBlocks.Pop() : new byte[BlockSize]; - return Result; - } - private void FreeBlock(byte[] block) - { - if (m_UsedBlocks.Count < MaxBlocksInCache) - m_UsedBlocks.Push(block); - } - private byte[] GetWBlock() - { - byte[] Result = null; - if (m_WPos < BlockSize && m_Blocks.Count > 0) - Result = (byte[])m_Blocks[m_Blocks.Count - 1]; - else - { - Result = AllocBlock(); - m_Blocks.Add(Result); - m_WPos = 0; - } - return Result; - } - - // Stream members - public override bool CanRead - { - get { return true; } - } - public override bool CanSeek - { - get { return false; } - } - public override bool CanWrite - { - get { return true; } - } - public override long Length - { - get - { - lock (this) - return m_Size; - } - } - public override long Position - { - get { throw new InvalidOperationException(); } - set { throw new InvalidOperationException(); } - } - public override void Close() - { - Flush(); - } - public override void Flush() - { - lock (this) - { - foreach (byte[] block in m_Blocks) - FreeBlock(block); - m_Blocks.Clear(); - m_RPos = 0; - m_WPos = 0; - m_Size = 0; - } - } - public override void SetLength(long len) - { - throw new InvalidOperationException(); - } - public override long Seek(long pos, SeekOrigin o) - { - throw new InvalidOperationException(); - } - public override int Read(byte[] buf, int ofs, int count) - { - lock (this) - { - int Result = Peek(buf, ofs, count); - Advance(Result); - return Result; - } - } - public override void Write(byte[] buf, int ofs, int count) - { - lock (this) - { - int Left = count; - while (Left > 0) - { - int ToWrite = Math.Min(BlockSize - m_WPos, Left); - Array.Copy(buf, ofs + count - Left, GetWBlock(), m_WPos, ToWrite); - m_WPos += ToWrite; - Left -= ToWrite; - } - m_Size += count; - } - } - - // extra stuff - public int Advance(int count) - { - lock (this) - { - int SizeLeft = count; - while (SizeLeft > 0 && m_Size > 0) - { - if (m_RPos == BlockSize) - { - m_RPos = 0; - FreeBlock((byte[])m_Blocks[0]); - m_Blocks.RemoveAt(0); - } - int ToFeed = m_Blocks.Count == 1 ? Math.Min(m_WPos - m_RPos, SizeLeft) : Math.Min(BlockSize - m_RPos, SizeLeft); - m_RPos += ToFeed; - SizeLeft -= ToFeed; - m_Size -= ToFeed; - } - return count - SizeLeft; - } - } - public int Peek(byte[] buf, int ofs, int count) - { - lock (this) - { - int SizeLeft = count; - int TempBlockPos = m_RPos; - int TempSize = m_Size; - - int CurrentBlock = 0; - while (SizeLeft > 0 && TempSize > 0) - { - if (TempBlockPos == BlockSize) - { - TempBlockPos = 0; - CurrentBlock++; - } - int Upper = CurrentBlock < m_Blocks.Count - 1 ? BlockSize : m_WPos; - int ToFeed = Math.Min(Upper - TempBlockPos, SizeLeft); - Array.Copy((byte[])m_Blocks[CurrentBlock], TempBlockPos, buf, ofs + count - SizeLeft, ToFeed); - SizeLeft -= ToFeed; - TempBlockPos += ToFeed; - TempSize -= ToFeed; - } - return count - SizeLeft; - } - } - } -} diff --git a/Halovision/FormatChunk.cs b/Halovision/FormatChunk.cs deleted file mode 100644 index f83eef4..0000000 --- a/Halovision/FormatChunk.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace lucidcode.LucidScribe.Plugin.Halovision -{ - internal class FormatChunk - { - private ushort _bitsPerSample; - private ushort _channels; - private uint _frequency; - private const string CHUNK_ID = "fmt "; - - public string ChunkId { get; private set; } - public UInt32 ChunkSize { get; private set; } - public UInt16 FormatTag { get; private set; } - - public UInt16 Channels - { - get { return _channels; } - set { _channels = value; RecalcBlockSizes(); } - } - - public UInt32 Frequency - { - get { return _frequency; } - set { _frequency = value; RecalcBlockSizes(); } - } - - public UInt32 AverageBytesPerSec { get; private set; } - public UInt16 BlockAlign { get; private set; } - - public UInt16 BitsPerSample - { - get { return _bitsPerSample; } - set { _bitsPerSample = value; RecalcBlockSizes(); } - } - - public FormatChunk() - { - ChunkId = CHUNK_ID; - ChunkSize = 16; - FormatTag = 1; // MS PCM (Uncompressed wave file) - Channels = 2; // Default to stereo - Frequency = 44100; // Default to 44100hz - BitsPerSample = 16; // Default to 16bits - RecalcBlockSizes(); - } - - private void RecalcBlockSizes() - { - BlockAlign = (UInt16)(_channels * (_bitsPerSample / 8)); - AverageBytesPerSec = _frequency * BlockAlign; - } - - public byte[] GetBytes() - { - List chunkBytes = new List(); - - chunkBytes.AddRange(Encoding.ASCII.GetBytes(ChunkId)); - chunkBytes.AddRange(BitConverter.GetBytes(ChunkSize)); - chunkBytes.AddRange(BitConverter.GetBytes(FormatTag)); - chunkBytes.AddRange(BitConverter.GetBytes(Channels)); - chunkBytes.AddRange(BitConverter.GetBytes(Frequency)); - chunkBytes.AddRange(BitConverter.GetBytes(AverageBytesPerSec)); - chunkBytes.AddRange(BitConverter.GetBytes(BlockAlign)); - chunkBytes.AddRange(BitConverter.GetBytes(BitsPerSample)); - - return chunkBytes.ToArray(); - } - - public UInt32 Length() - { - return (UInt32)GetBytes().Length; - } - } -} diff --git a/Halovision/Halovision.csproj b/Halovision/Halovision.csproj index 9fe352e..dad9482 100644 --- a/Halovision/Halovision.csproj +++ b/Halovision/Halovision.csproj @@ -210,17 +210,13 @@ - - - True True Resources.resx - - + Form diff --git a/Halovision/PluginHandler.cs b/Halovision/PluginHandler.cs index 7a96dd5..9ea1ff7 100644 --- a/Halovision/PluginHandler.cs +++ b/Halovision/PluginHandler.cs @@ -274,6 +274,9 @@ namespace Vision { public class PluginHandler : lucidcode.LucidScribe.Interface.LucidPluginBase { + private IWavePlayer player; + private SineWaveProvider sineProvider; + public override string Name { get @@ -284,6 +287,14 @@ public override string Name public override bool Initialize() { + sineProvider = new SineWaveProvider(); + + var waveOutEvent = new WaveOutEvent(); + waveOutEvent.NumberOfBuffers = 2; + waveOutEvent.DesiredLatency = 100; + player = waveOutEvent; + player.Init(new SampleToWaveProvider(sineProvider)); + return Device.Initialize(); } @@ -295,8 +306,18 @@ public override double Value if (vision > 999) { vision = 999; } if (vision < 0) { vision = 0; } - if (Device.Auralize && vision > 0) { + if (Device.Auralize) { + if (player.PlaybackState != PlaybackState.Playing) + { + player.Play(); + } Auralize(vision); + } else + { + if (player.PlaybackState == PlaybackState.Playing) + { + player.Pause(); + } } return vision; @@ -305,27 +326,17 @@ public override double Value private void Auralize(double frequency) { - try - { - var sineWave = new NAudio.Wave.SampleProviders.SignalGenerator() - { - Gain = 0.1, - Frequency = 256 + frequency, - Type = SignalGeneratorType.Sin - }.Take(TimeSpan.FromMilliseconds(128)); - - var waveOutEvent = new WaveOutEvent(); - waveOutEvent.Pause(); - waveOutEvent.Init(sineWave); - waveOutEvent.Play(); - } catch (Exception ex) - { - - } + if (frequency > 0) frequency += 128; + sineProvider.Frequency = frequency; } public override void Dispose() { + if (player != null) + { + player.Dispose(); + player = null; + } Device.Dispose(); } } diff --git a/Halovision/Properties/AssemblyInfo.cs b/Halovision/Properties/AssemblyInfo.cs index d2299fd..a3f7959 100644 --- a/Halovision/Properties/AssemblyInfo.cs +++ b/Halovision/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ // 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.2.3.0")] -[assembly: AssemblyFileVersion("1.2.3.0")] +[assembly: AssemblyVersion("1.2.4.0")] +[assembly: AssemblyFileVersion("1.2.4.0")] diff --git a/Halovision/SignalGenerator.cs b/Halovision/SignalGenerator.cs deleted file mode 100644 index 16cefe2..0000000 --- a/Halovision/SignalGenerator.cs +++ /dev/null @@ -1,138 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace lucidcode.LucidScribe.Plugin.Halovision -{ - public class SignalGenerator - { - - private SignalType signalType = SignalType.Sine; - /// - /// Signal Type. - /// - public SignalType SignalType - { - get { return signalType; } - set { signalType = value; } - } - - private float frequency = 1f; - /// - /// Signal Frequency. - /// - public float Frequency - { - get { return frequency; } - set { frequency = value; } - } - - private float phase = 0f; - /// - /// Signal Phase. - /// - public float Phase - { - get { return phase; } - set { phase = value; } - } - - private float amplitude = 1f; - /// - /// Signal Amplitude. - /// - public float Amplitude - { - get { return amplitude; } - set { amplitude = value; } - - } - - private float offset = 0f; - /// - /// Signal Offset. - /// - public float Offset - { - get { return offset; } - set { offset = value; } - } - - private float invert = 1; // Yes=-1, No=1 - /// - /// Signal Inverted? - /// - public bool Invert - { - get { return invert == -1; } - set { invert = value ? -1 : 1; } - } - - /// - /// Time the signal generator was started - /// - private long startTime = Stopwatch.GetTimestamp(); - - /// - /// Ticks per second on this CPU - /// - private long ticksPerSecond = Stopwatch.Frequency; - - public SignalGenerator(SignalType initialSignalType) - { - signalType = initialSignalType; - } - - public SignalGenerator() { } - - public float GetValue(float time) - { - float value = 0f; - float t = frequency * time + phase; - switch (signalType) - { - case SignalType.Sine: // sin( 2 * pi * t ) - value = (float)Math.Sin(2f * Math.PI * t); - break; - case SignalType.Square: // sign( sin( 2 * pi * t ) ) - value = Math.Sign(Math.Sin(2f * Math.PI * t)); - break; - case SignalType.Triangle: - // 2 * abs( t - 2 * floor( t / 2 ) - 1 ) - 1 - value = 1f - 4f * (float)Math.Abs - (Math.Round(t - 0.25f) - (t - 0.25f)); - break; - case SignalType.Sawtooth: - // 2 * ( t/a - floor( t/a + 1/2 ) ) - value = 2f * (t - (float)Math.Floor(t + 0.5f)); - break; - } - - return (invert * amplitude * value + offset); - } - - public float GetValue() - { - float time = (float)(Stopwatch.GetTimestamp() - startTime) - / ticksPerSecond; - return GetValue(time); - } - - public void Reset() - { - startTime = Stopwatch.GetTimestamp(); - } - - } - - public enum SignalType - { - Sine, - Square, - Triangle, - Sawtooth - } -} diff --git a/Halovision/SineGenerator.cs b/Halovision/SineGenerator.cs deleted file mode 100644 index b9dc240..0000000 --- a/Halovision/SineGenerator.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; - -namespace lucidcode.LucidScribe.Plugin.Halovision -{ - internal class SineGenerator - { - private readonly double _frequency; - private short[] _dataBuffer; - - public short[] Data { get { return _dataBuffer; } } - - public SineGenerator(double frequency) - { - _frequency = frequency; - GenerateData(); - } - - private void GenerateData() - { - UInt32 sampleRate = 44100; - - uint bufferSize = sampleRate / 10; - _dataBuffer = new short[bufferSize]; - - int amplitude = 32760; - - double timePeriod = (Math.PI * 2 * _frequency) / - (sampleRate); - - for (uint index = 0; index < bufferSize - 1; index++) - { - _dataBuffer[index] = Convert.ToInt16(amplitude * - Math.Sin(timePeriod * index)); - } - } - } -} diff --git a/Halovision/SineWaveProvider.cs b/Halovision/SineWaveProvider.cs new file mode 100644 index 0000000..1b7aaff --- /dev/null +++ b/Halovision/SineWaveProvider.cs @@ -0,0 +1,75 @@ +using NAudio.Wave; +using System; + +namespace lucidcode.LucidScribe.Plugin.Halovision +{ + internal class SineWaveProvider : ISampleProvider + { + private readonly float[] waveTable; + private double phase; + private double currentPhaseStep; + private double targetPhaseStep; + private double frequency; + private double phaseStepDelta; + private bool seekFreq; + + public SineWaveProvider(int sampleRate = 44100) + { + WaveFormat = WaveFormat.CreateIeeeFloatWaveFormat(sampleRate, 1); + waveTable = new float[sampleRate]; + for (int index = 0; index < sampleRate; ++index) + waveTable[index] = (float)Math.Sin(2 * Math.PI * (double)index / sampleRate); + Frequency = 1000f; + Volume = 1f; + PortamentoTime = 0.1; + } + + public double PortamentoTime { get; set; } + + public double Frequency + { + get + { + return frequency; + } + set + { + frequency = value; + seekFreq = true; + } + } + + public float Volume { get; set; } + + public WaveFormat WaveFormat { get; private set; } + + public int Read(float[] buffer, int offset, int count) + { + if (seekFreq) + { + targetPhaseStep = waveTable.Length * (frequency / WaveFormat.SampleRate); + + phaseStepDelta = (targetPhaseStep - currentPhaseStep) / (WaveFormat.SampleRate * PortamentoTime); + seekFreq = false; + } + var vol = Volume; + for (int n = 0; n < count; ++n) + { + int waveTableIndex = (int)phase % waveTable.Length; + buffer[n + offset] = waveTable[waveTableIndex] * vol; + phase += currentPhaseStep; + if (phase > waveTable.Length) + phase -= waveTable.Length; + if (currentPhaseStep != targetPhaseStep) + { + currentPhaseStep += phaseStepDelta; + if (phaseStepDelta > 0.0 && currentPhaseStep > targetPhaseStep) + currentPhaseStep = targetPhaseStep; + else if (phaseStepDelta < 0.0 && currentPhaseStep < targetPhaseStep) + currentPhaseStep = targetPhaseStep; + } + } + return count; + } + } +} diff --git a/Installer/Lucid Scribe Halovision.vdproj b/Installer/Lucid Scribe Halovision.vdproj index 6d596fc..3ac3ff8 100644 --- a/Installer/Lucid Scribe Halovision.vdproj +++ b/Installer/Lucid Scribe Halovision.vdproj @@ -11352,15 +11352,15 @@ { "Name" = "8:Microsoft Visual Studio" "ProductName" = "8:Lucid Scribe Halovision" - "ProductCode" = "8:{28D04893-3186-45CA-8927-AD072FE69696}" - "PackageCode" = "8:{389BFD74-36D1-46A4-9D83-257CBB7550F0}" + "ProductCode" = "8:{0A90DC5A-E6FE-4BD8-A9F4-E377E67BD83F}" + "PackageCode" = "8:{C140AB67-58D5-4B5E-9B04-41683F4AD0BB}" "UpgradeCode" = "8:{CAAB2187-AD23-435C-A3DB-568744247625}" "AspNetVersion" = "8:4.0.30319.0" "RestartWWWService" = "11:FALSE" "RemovePreviousVersions" = "11:TRUE" "DetectNewerInstalledVersion" = "11:TRUE" "InstallAllUsers" = "11:TRUE" - "ProductVersion" = "8:1.2.3" + "ProductVersion" = "8:1.2.4" "Manufacturer" = "8:lucidcode" "ARPHELPTELEPHONE" = "8:" "ARPHELPLINK" = "8:http://www.lucidcode.com/Contact"