-
Notifications
You must be signed in to change notification settings - Fork 0
/
StringSynthesiser.cs
69 lines (55 loc) · 2.14 KB
/
StringSynthesiser.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Guitarsharp
{
[Serializable]
internal class StringSynthesiser
{
private readonly double decay = 0.998;
private double amplitude = 0.0;
private List<float> excitationSample, delayLine;
private int pos = 0;
public StringSynthesiser(double sampleRate, double frequencyInHz)
{
PrepareSynthesiserState(sampleRate, frequencyInHz);
}
private void PrepareSynthesiserState(double sampleRate, double frequencyInHz)
{
int delayLineLength = (int)Math.Round(sampleRate / frequencyInHz);
if (delayLineLength <= 50)
throw new InvalidOperationException("Increase sample rate or decrease frequency!");
delayLine = new List<float>(new float[delayLineLength]);
excitationSample = new List<float>(new float[delayLineLength]);
var random = new Random();
for (int i = 0; i < delayLineLength; i++)
{
excitationSample[i] = (float)(random.NextDouble() * 2.0 - 1.0);
}
}
public void StringPlucked(float pluckPosition)
{
if (pluckPosition < 0.0 || pluckPosition > 1.0)
throw new ArgumentOutOfRangeException(nameof(pluckPosition));
amplitude = Math.Sin(Math.PI * pluckPosition);
for (int i = 0; i < excitationSample.Count; i++)
{
delayLine[i] = (float)(amplitude * excitationSample[i]);
}
}
public float[] GenerateData(int numSamples)
{
float[] output = new float[numSamples];
for (int i = 0; i < numSamples; i++)
{
int nextPos = (pos + 1) % delayLine.Count;
delayLine[nextPos] = (float)(decay * 0.5 * (delayLine[nextPos] + delayLine[pos]));
output[i] = delayLine[pos];
pos = nextPos;
}
return output;
}
}
}