some new algorithms and some new stuff. sounds increased!
This commit is contained in:
74
simulations/SortVisualizer/Algorithms/BeadSort.cs
Normal file
74
simulations/SortVisualizer/Algorithms/BeadSort.cs
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SortVisualizer;
|
||||||
|
|
||||||
|
public class BeadSort : ISortAlgorithm
|
||||||
|
{
|
||||||
|
public string Name => "Bead Sort";
|
||||||
|
public BeadSort() { }
|
||||||
|
|
||||||
|
public async Task Sort(int[] array, Action refresh, int delay, Action<int> playSound, CancellationToken token)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int n = array.Length;
|
||||||
|
if (n == 0) return;
|
||||||
|
|
||||||
|
int max = 0;
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
token.ThrowIfCancellationRequested();
|
||||||
|
if (array[i] > max) max = array[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool[,] beads = new bool[n, max];
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
token.ThrowIfCancellationRequested();
|
||||||
|
for (int j = 0; j < array[i]; j++)
|
||||||
|
beads[i, j] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < max; j++)
|
||||||
|
{
|
||||||
|
token.ThrowIfCancellationRequested();
|
||||||
|
int sum = 0;
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
if (beads[i, j]) sum++;
|
||||||
|
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
beads[i, j] = i >= n - sum;
|
||||||
|
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
array[i] = 0;
|
||||||
|
for (int k = 0; k < max; k++)
|
||||||
|
if (beads[i, k]) array[i]++;
|
||||||
|
playSound?.Invoke(array[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh?.Invoke();
|
||||||
|
await Task.Delay(delay, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
token.ThrowIfCancellationRequested();
|
||||||
|
int count = 0;
|
||||||
|
for (int j = 0; j < max; j++)
|
||||||
|
if (beads[i, j]) count++;
|
||||||
|
array[i] = count;
|
||||||
|
|
||||||
|
playSound?.Invoke(array[i]);
|
||||||
|
refresh?.Invoke();
|
||||||
|
await Task.Delay(delay, token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (TaskCanceledException)
|
||||||
|
{
|
||||||
|
// Safe cancellation, just exit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
77
simulations/SortVisualizer/Algorithms/RadixSort.cs
Normal file
77
simulations/SortVisualizer/Algorithms/RadixSort.cs
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SortVisualizer;
|
||||||
|
|
||||||
|
public class RadixSort : ISortAlgorithm
|
||||||
|
{
|
||||||
|
public string Name => "Radix Sort";
|
||||||
|
public RadixSort() { }
|
||||||
|
|
||||||
|
public async Task Sort(int[] array, Action refresh, int delay, Action<int> playSound, CancellationToken token)
|
||||||
|
{
|
||||||
|
int max = GetMax(array);
|
||||||
|
int exp = 1;
|
||||||
|
|
||||||
|
while (max / exp > 0)
|
||||||
|
{
|
||||||
|
token.ThrowIfCancellationRequested();
|
||||||
|
await CountSort(array, exp, refresh, delay, playSound, token);
|
||||||
|
exp *= 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int GetMax(int[] array)
|
||||||
|
{
|
||||||
|
int max = array[0];
|
||||||
|
for (int i = 1; i < array.Length; i++)
|
||||||
|
if (array[i] > max) max = array[i];
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CountSort(int[] array, int exp, Action refresh, int delay, Action<int> playSound, CancellationToken token)
|
||||||
|
{
|
||||||
|
int n = array.Length;
|
||||||
|
int[] output = new int[n];
|
||||||
|
int[] count = new int[10]; // digits 0-9
|
||||||
|
|
||||||
|
// Count occurrences of digits
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
token.ThrowIfCancellationRequested();
|
||||||
|
int index = (array[i] / exp) % 10;
|
||||||
|
count[index]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert count to positions
|
||||||
|
for (int i = 1; i < 10; i++)
|
||||||
|
{
|
||||||
|
count[i] += count[i - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the output array
|
||||||
|
for (int i = n - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
token.ThrowIfCancellationRequested();
|
||||||
|
int index = (array[i] / exp) % 10;
|
||||||
|
output[count[index] - 1] = array[i];
|
||||||
|
count[index]--;
|
||||||
|
|
||||||
|
// Visualize
|
||||||
|
refresh?.Invoke();
|
||||||
|
playSound?.Invoke(array[i]);
|
||||||
|
await Task.Delay(10, token); // small delay per operation
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy output to original array
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
token.ThrowIfCancellationRequested();
|
||||||
|
array[i] = output[i];
|
||||||
|
refresh?.Invoke();
|
||||||
|
playSound?.Invoke(array[i]);
|
||||||
|
await Task.Delay(delay, token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,4 +8,8 @@
|
|||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="NAudio" Version="2.2.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
@@ -1,13 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Media;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
using NAudio.Wave;
|
||||||
|
|
||||||
namespace SortVisualizer;
|
namespace SortVisualizer;
|
||||||
|
|
||||||
@@ -22,13 +20,13 @@ public class VisualizerForm : Form
|
|||||||
Button startButton, stopButton, shuffleButton;
|
Button startButton, stopButton, shuffleButton;
|
||||||
TrackBar speedSlider;
|
TrackBar speedSlider;
|
||||||
CheckBox soundToggle;
|
CheckBox soundToggle;
|
||||||
Label speedLabel, statusLabel;
|
|
||||||
|
|
||||||
List<ISortAlgorithm> algorithms;
|
List<ISortAlgorithm> algorithms;
|
||||||
CancellationTokenSource? cts;
|
CancellationTokenSource? cts;
|
||||||
|
|
||||||
Dictionary<int, byte[]> toneCache = new();
|
// Audio
|
||||||
SemaphoreSlim soundSemaphore = new(1, 1); // prevent sound overlap
|
BufferedWaveProvider? waveProvider;
|
||||||
|
WaveOutEvent? waveOut;
|
||||||
|
|
||||||
int highlightedIndex1 = -1;
|
int highlightedIndex1 = -1;
|
||||||
int highlightedIndex2 = -1;
|
int highlightedIndex2 = -1;
|
||||||
@@ -41,11 +39,13 @@ public class VisualizerForm : Form
|
|||||||
Width = 1000;
|
Width = 1000;
|
||||||
Height = 600;
|
Height = 600;
|
||||||
|
|
||||||
algorithms = new() { new BubbleSort(), new InsertionSort(), new BogoSort(),
|
algorithms = new()
|
||||||
new MergeSort() , new StoogeSort()
|
{
|
||||||
};
|
new BubbleSort(), new InsertionSort(), new BogoSort(),
|
||||||
|
new MergeSort(), new StoogeSort(), new RadixSort(),
|
||||||
|
new BeadSort()
|
||||||
|
};
|
||||||
|
|
||||||
// --- Top Control Panel ---
|
|
||||||
var topPanel = new FlowLayoutPanel
|
var topPanel = new FlowLayoutPanel
|
||||||
{
|
{
|
||||||
Dock = DockStyle.Top,
|
Dock = DockStyle.Top,
|
||||||
@@ -68,7 +68,6 @@ public class VisualizerForm : Form
|
|||||||
|
|
||||||
soundToggle = new CheckBox { Width = 100, Height = buttonHeight, Text = "Sound On", Checked = true };
|
soundToggle = new CheckBox { Width = 100, Height = buttonHeight, Text = "Sound On", Checked = true };
|
||||||
|
|
||||||
speedLabel = new Label { Width = 60, Height = buttonHeight, Text = "Speed: 10", TextAlign = ContentAlignment.MiddleCenter };
|
|
||||||
speedSlider = new TrackBar
|
speedSlider = new TrackBar
|
||||||
{
|
{
|
||||||
Width = 250,
|
Width = 250,
|
||||||
@@ -81,12 +80,10 @@ public class VisualizerForm : Form
|
|||||||
Height = buttonHeight
|
Height = buttonHeight
|
||||||
};
|
};
|
||||||
|
|
||||||
statusLabel = new Label { Width = 150, Height = buttonHeight, Text = "Idle", TextAlign = ContentAlignment.MiddleRight };
|
|
||||||
|
|
||||||
topPanel.Controls.AddRange(new Control[]
|
topPanel.Controls.AddRange(new Control[]
|
||||||
{
|
{
|
||||||
algoSelector, startButton, stopButton, shuffleButton,
|
algoSelector, startButton, stopButton, shuffleButton,
|
||||||
soundToggle, speedLabel, speedSlider, statusLabel
|
soundToggle, speedSlider
|
||||||
});
|
});
|
||||||
|
|
||||||
Controls.Add(topPanel);
|
Controls.Add(topPanel);
|
||||||
@@ -94,7 +91,6 @@ public class VisualizerForm : Form
|
|||||||
speedSlider.ValueChanged += (s, e) =>
|
speedSlider.ValueChanged += (s, e) =>
|
||||||
{
|
{
|
||||||
delay = 101 - speedSlider.Value;
|
delay = 101 - speedSlider.Value;
|
||||||
speedLabel.Text = $"Speed: {speedSlider.Value}";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
startButton.Click += async (s, e) => await StartSort();
|
startButton.Click += async (s, e) => await StartSort();
|
||||||
@@ -112,7 +108,6 @@ public class VisualizerForm : Form
|
|||||||
array = Enumerable.Range(1, 100).OrderBy(_ => rand.Next()).ToArray();
|
array = Enumerable.Range(1, 100).OrderBy(_ => rand.Next()).ToArray();
|
||||||
highlightedIndex1 = highlightedIndex2 = -1;
|
highlightedIndex1 = highlightedIndex2 = -1;
|
||||||
Invalidate();
|
Invalidate();
|
||||||
statusLabel.Text = "Shuffled!";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async Task StartSort()
|
async Task StartSort()
|
||||||
@@ -121,28 +116,39 @@ public class VisualizerForm : Form
|
|||||||
sorting = true;
|
sorting = true;
|
||||||
cts = new CancellationTokenSource();
|
cts = new CancellationTokenSource();
|
||||||
|
|
||||||
var algo = (ISortAlgorithm)algoSelector.SelectedItem!;
|
var algo = algoSelector.SelectedItem as ISortAlgorithm;
|
||||||
statusLabel.Text = $"Sorting ( {algo.Name} )...";
|
if (algo == null)
|
||||||
|
{
|
||||||
|
sorting = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (soundToggle.Checked)
|
||||||
|
{
|
||||||
|
InitializeAudio();
|
||||||
|
if (waveProvider != null)
|
||||||
|
{
|
||||||
|
_ = Task.Run(() => AudioLoopAsync(waveProvider, cts.Token));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await algo.Sort(
|
await algo.Sort(
|
||||||
array,
|
array,
|
||||||
() => Invalidate(), // keep original signature
|
() => Invalidate(),
|
||||||
delay,
|
delay,
|
||||||
value => { if (soundToggle.Checked) _ = PlaySoundAsync(value); },
|
value => { highlightedIndex1 = value; },
|
||||||
cts.Token
|
cts.Token
|
||||||
);
|
);
|
||||||
|
|
||||||
highlightedIndex1 = highlightedIndex2 = -1;
|
highlightedIndex1 = highlightedIndex2 = -1;
|
||||||
Invalidate();
|
Invalidate();
|
||||||
|
|
||||||
if (!cts.Token.IsCancellationRequested)
|
|
||||||
statusLabel.Text = "Done!";
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
sorting = false;
|
sorting = false;
|
||||||
|
StopAudio();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,7 +159,76 @@ public class VisualizerForm : Form
|
|||||||
sorting = false;
|
sorting = false;
|
||||||
highlightedIndex1 = highlightedIndex2 = -1;
|
highlightedIndex1 = highlightedIndex2 = -1;
|
||||||
Invalidate();
|
Invalidate();
|
||||||
statusLabel.Text = "Stopped.";
|
StopAudio();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializeAudio()
|
||||||
|
{
|
||||||
|
waveProvider = new BufferedWaveProvider(new WaveFormat(44100, 16, 1))
|
||||||
|
{
|
||||||
|
BufferDuration = TimeSpan.FromSeconds(5)
|
||||||
|
};
|
||||||
|
|
||||||
|
waveOut = new WaveOutEvent();
|
||||||
|
waveOut.Init(waveProvider);
|
||||||
|
waveOut.Play();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StopAudio()
|
||||||
|
{
|
||||||
|
waveOut?.Stop();
|
||||||
|
waveOut?.Dispose();
|
||||||
|
waveOut = null;
|
||||||
|
waveProvider = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async Task AudioLoopAsync(BufferedWaveProvider provider, CancellationToken token)
|
||||||
|
{
|
||||||
|
short amplitude = 8000;
|
||||||
|
int sampleRate = 44100;
|
||||||
|
int chunkSamples = 512;
|
||||||
|
var buffer = new byte[chunkSamples * 2];
|
||||||
|
double phase = 0;
|
||||||
|
|
||||||
|
while (!token.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
// Calculate frequency based on highlighted element or average
|
||||||
|
int freq = 220;
|
||||||
|
if (highlightedIndex1 >= 0 && highlightedIndex1 < array.Length)
|
||||||
|
{
|
||||||
|
freq = 220 + array[highlightedIndex1] * 15; // Rising pitch based on value
|
||||||
|
}
|
||||||
|
else if (array.Length > 0)
|
||||||
|
{
|
||||||
|
freq = 220 + (int)array.Average() * 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int n = 0; n < chunkSamples; n++)
|
||||||
|
{
|
||||||
|
double sample = Math.Sin(phase);
|
||||||
|
phase += 2 * Math.PI * freq / sampleRate;
|
||||||
|
|
||||||
|
// Keep phase in reasonable range
|
||||||
|
if (phase > 2 * Math.PI * 1000)
|
||||||
|
phase -= 2 * Math.PI * 1000;
|
||||||
|
|
||||||
|
short s = (short)(sample * amplitude);
|
||||||
|
buffer[n * 2] = (byte)(s & 0xFF);
|
||||||
|
buffer[n * 2 + 1] = (byte)((s >> 8) & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
int space = provider.BufferLength - provider.BufferedBytes;
|
||||||
|
if (space >= buffer.Length)
|
||||||
|
{
|
||||||
|
provider.AddSamples(buffer, 0, buffer.Length);
|
||||||
|
}
|
||||||
|
else if (space > 0)
|
||||||
|
{
|
||||||
|
provider.AddSamples(buffer, buffer.Length - space, space);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.Delay(1, token);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnPaint(PaintEventArgs e)
|
protected override void OnPaint(PaintEventArgs e)
|
||||||
@@ -163,15 +238,21 @@ public class VisualizerForm : Form
|
|||||||
|
|
||||||
int offsetY = 50;
|
int offsetY = 50;
|
||||||
int marginX = 20;
|
int marginX = 20;
|
||||||
|
int paddingTop = 5;
|
||||||
|
int paddingBottom = 5;
|
||||||
|
|
||||||
if (array.Length == 0) return;
|
if (array.Length == 0) return;
|
||||||
|
|
||||||
int barWidth = (ClientSize.Width - 2 * marginX) / array.Length;
|
int barWidth = (ClientSize.Width - 2 * marginX) / array.Length;
|
||||||
int availableHeight = ClientSize.Height - offsetY;
|
int top = offsetY + paddingTop;
|
||||||
|
int bottom = ClientSize.Height - paddingBottom;
|
||||||
|
int availableHeight = bottom - top;
|
||||||
|
|
||||||
|
int maxVal = array.Max();
|
||||||
|
|
||||||
for (int i = 0; i < array.Length; i++)
|
for (int i = 0; i < array.Length; i++)
|
||||||
{
|
{
|
||||||
int height = (int)(array[i] * (availableHeight / (float)array.Length));
|
int height = (int)Math.Round(array[i] * (availableHeight / (float)maxVal));
|
||||||
Brush brush = Brushes.LightGreen;
|
Brush brush = Brushes.LightGreen;
|
||||||
|
|
||||||
if (sorting)
|
if (sorting)
|
||||||
@@ -181,109 +262,10 @@ public class VisualizerForm : Form
|
|||||||
else brush = Brushes.DeepSkyBlue;
|
else brush = Brushes.DeepSkyBlue;
|
||||||
}
|
}
|
||||||
|
|
||||||
g.FillRectangle(brush, marginX + i * barWidth, ClientSize.Height - height, barWidth - 1, height);
|
int y = bottom - height;
|
||||||
|
if (y < top) y = top;
|
||||||
|
|
||||||
|
g.FillRectangle(brush, marginX + i * barWidth, y, barWidth - 1, height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async Task PlaySoundAsync(int value)
|
|
||||||
{
|
|
||||||
// Use semaphore to prevent overlapping sounds
|
|
||||||
if (!await soundSemaphore.WaitAsync(0))
|
|
||||||
return; // skip if already playing
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int freq = 220 + (int)(value * 12.0);
|
|
||||||
int durationMs = 10;
|
|
||||||
|
|
||||||
if (!toneCache.TryGetValue(freq, out var wav))
|
|
||||||
{
|
|
||||||
wav = GenerateToneWav(freq, durationMs, 44100);
|
|
||||||
|
|
||||||
// Limit cache size
|
|
||||||
if (toneCache.Count > 200)
|
|
||||||
toneCache.Clear();
|
|
||||||
|
|
||||||
toneCache[freq] = wav;
|
|
||||||
}
|
|
||||||
|
|
||||||
await Task.Run(() =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using var ms = new MemoryStream(wav);
|
|
||||||
using var player = new SoundPlayer(ms);
|
|
||||||
player.PlaySync(); // blocks on background thread
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
|
||||||
Console.Beep(freq, durationMs);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
soundSemaphore.Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (disposing)
|
|
||||||
{
|
|
||||||
cts?.Dispose();
|
|
||||||
soundSemaphore?.Dispose();
|
|
||||||
}
|
|
||||||
base.Dispose(disposing);
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Tone Generation
|
|
||||||
|
|
||||||
public static byte[] GenerateToneWav(int frequency, int durationMs, int sampleRate = 44100, double amplitude = 0.25)
|
|
||||||
{
|
|
||||||
int samples = (int)((durationMs / 1000.0) * sampleRate);
|
|
||||||
using var ms = new MemoryStream();
|
|
||||||
using var bw = new BinaryWriter(ms);
|
|
||||||
|
|
||||||
short numChannels = 1;
|
|
||||||
short bitsPerSample = 16;
|
|
||||||
int byteRate = sampleRate * numChannels * bitsPerSample / 8;
|
|
||||||
short blockAlign = (short)(numChannels * bitsPerSample / 8);
|
|
||||||
int dataSize = samples * numChannels * (bitsPerSample / 8);
|
|
||||||
|
|
||||||
bw.Write(System.Text.Encoding.ASCII.GetBytes("RIFF"));
|
|
||||||
bw.Write(36 + dataSize);
|
|
||||||
bw.Write(System.Text.Encoding.ASCII.GetBytes("WAVE"));
|
|
||||||
|
|
||||||
bw.Write(System.Text.Encoding.ASCII.GetBytes("fmt "));
|
|
||||||
bw.Write(16);
|
|
||||||
bw.Write((short)1);
|
|
||||||
bw.Write(numChannels);
|
|
||||||
bw.Write(sampleRate);
|
|
||||||
bw.Write(byteRate);
|
|
||||||
bw.Write(blockAlign);
|
|
||||||
bw.Write(bitsPerSample);
|
|
||||||
|
|
||||||
bw.Write(System.Text.Encoding.ASCII.GetBytes("data"));
|
|
||||||
bw.Write(dataSize);
|
|
||||||
|
|
||||||
double twoPiF = 2 * Math.PI * frequency;
|
|
||||||
for (int n = 0; n < samples; n++)
|
|
||||||
{
|
|
||||||
double t = n / (double)sampleRate;
|
|
||||||
double sample = amplitude * Math.Sin(twoPiF * t);
|
|
||||||
short s = (short)Math.Max(short.MinValue, Math.Min(short.MaxValue, sample * short.MaxValue));
|
|
||||||
bw.Write(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
bw.Flush();
|
|
||||||
return ms.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user