mirror of
https://github.com/Ale32bit/Capy64.git
synced 2025-01-18 18:46:43 +00:00
Fix audio that was fucked up since the beginning
This commit is contained in:
parent
5e95e74545
commit
e3616e4ac6
3 changed files with 58 additions and 102 deletions
|
@ -241,7 +241,7 @@ local function bootScreen()
|
|||
end
|
||||
end
|
||||
|
||||
audio.beep(1000, 0.4, 0.2, "square")
|
||||
audio.beep(1000, 0.2, 0.2, "square")
|
||||
|
||||
if shouldInstallOS() then
|
||||
installOS()
|
||||
|
|
|
@ -4,6 +4,8 @@ using System;
|
|||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -12,6 +14,15 @@ namespace Capy64.Core;
|
|||
|
||||
public class Audio : IDisposable
|
||||
{
|
||||
public enum Waveform
|
||||
{
|
||||
Sine,
|
||||
Square,
|
||||
Triangle,
|
||||
Sawtooth,
|
||||
Noise
|
||||
}
|
||||
|
||||
public const int SampleRate = 48000;
|
||||
public const AudioChannels Channels = AudioChannels.Mono;
|
||||
public readonly DynamicSoundEffectInstance Sound;
|
||||
|
@ -19,7 +30,6 @@ public class Audio : IDisposable
|
|||
private static readonly Random rng = new();
|
||||
public Audio()
|
||||
{
|
||||
GenerateSawtoothWave(440, 1);
|
||||
Sound = new DynamicSoundEffectInstance(SampleRate, Channels);
|
||||
}
|
||||
|
||||
|
@ -29,77 +39,63 @@ public class Audio : IDisposable
|
|||
return Sound.GetSampleDuration(buffer.Length);
|
||||
}
|
||||
|
||||
public static byte[] GenerateSineWave(double frequency, double time, double volume = 1d)
|
||||
public byte[] GenerateWave(Waveform form, double frequency, TimeSpan time)
|
||||
{
|
||||
var amplitude = 128 * volume;
|
||||
var timeStep = 1d / SampleRate;
|
||||
var size = Sound.GetSampleSizeInBytes(time);
|
||||
var buffer = new byte[size];
|
||||
|
||||
var buffer = new byte[(int)(SampleRate * time)];
|
||||
var ctime = 0d;
|
||||
for (int i = 0; i < buffer.Length; i++)
|
||||
var step = 1d / SampleRate;
|
||||
double x = 0;
|
||||
for (int i = 0; i < size; i += 2)
|
||||
{
|
||||
double angle = (Math.PI * frequency) * ctime;
|
||||
double factor = 0.5 * (Math.Sin(angle) + 1.0);
|
||||
buffer[i] = (byte)(amplitude * factor);
|
||||
ctime += timeStep;
|
||||
var value = form switch
|
||||
{
|
||||
Waveform.Sine => GetSinePoint(frequency, x),
|
||||
Waveform.Square => GetSquarePoint(frequency, x),
|
||||
Waveform.Triangle => GetTrianglePoint(frequency, x),
|
||||
Waveform.Sawtooth => GetSawtoothPoint(frequency, x),
|
||||
Waveform.Noise => rng.NextDouble() * 2 - 1,
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
Console.WriteLine(value);
|
||||
value = Math.Clamp(value, -1, 1);
|
||||
var sample = (short)(value >= 0.0f ? value * short.MaxValue : value * short.MinValue * -1);
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
{
|
||||
buffer[i] = (byte)(sample >> 8);
|
||||
buffer[i + 1] = (byte)sample;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer[i] = (byte)sample;
|
||||
buffer[i + 1] = (byte)(sample >> 8);
|
||||
}
|
||||
x += step;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public static double GetSinePoint(double frequency, double x)
|
||||
{
|
||||
return Math.Sin(x * 2 * Math.PI * frequency);
|
||||
}
|
||||
|
||||
private static double GetSquarePoint(double frequency, double x)
|
||||
{
|
||||
double v = 0;
|
||||
for (int k = 1; k <= 50; k++)
|
||||
{
|
||||
v += 1 / (2 * k - 1) * Math.Sin(frequency * 2 * Math.PI * (2 * k - 1) * x) / 2 + 0.5;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
public static byte[] GenerateSquareWave(double frequency, double time, double volume = 1d)
|
||||
{
|
||||
var amplitude = 128 * volume;
|
||||
var timeStep = 1d / SampleRate;
|
||||
frequency /= 2;
|
||||
|
||||
var buffer = new byte[(int)(SampleRate * time)];
|
||||
var ctime = 0d;
|
||||
for (int i = 0; i < buffer.Length; i++)
|
||||
{
|
||||
var v = GetSquarePoint(frequency, ctime);
|
||||
buffer[i] = (byte)(v * amplitude);
|
||||
ctime += timeStep;
|
||||
}
|
||||
return buffer;
|
||||
double v = GetSinePoint(frequency, x);
|
||||
return v > 0 ? 1 : -1;
|
||||
}
|
||||
|
||||
private static double GetTrianglePoint(double frequency, double x)
|
||||
{
|
||||
double v = 0;
|
||||
for (int k = 1; k <= 50; k++)
|
||||
for (int k = 1; k <= 25; k++)
|
||||
{
|
||||
v += (Math.Pow(-1, k) / Math.Pow(2 * k - 1, 2))
|
||||
* Math.Sin(2 * Math.PI * (frequency * 2 * k - 1) * x)
|
||||
/ 2 + 0.5;
|
||||
* Math.Sin(frequency * 2 * Math.PI * (2 * k - 1) * x);
|
||||
}
|
||||
return -(8 / (Math.PI * Math.PI)) * v;
|
||||
}
|
||||
|
||||
public static byte[] GenerateTriangleWave(double frequency, double time, double volume = 1d)
|
||||
{
|
||||
var amplitude = 128 * volume;
|
||||
var timeStep = 1d / SampleRate;
|
||||
frequency /= 2;
|
||||
|
||||
var buffer = new byte[(int)(SampleRate * time)];
|
||||
var ctime = 0d;
|
||||
for (int i = 0; i < buffer.Length; i++)
|
||||
{
|
||||
var x = GetTrianglePoint(frequency, ctime);
|
||||
buffer[i] = (byte)(amplitude * x);
|
||||
ctime += timeStep;
|
||||
}
|
||||
return buffer;
|
||||
return -(8 / Math.Pow(Math.PI, 2)) * v;
|
||||
}
|
||||
|
||||
private static double GetSawtoothPoint(double frequency, double x)
|
||||
|
@ -107,43 +103,9 @@ public class Audio : IDisposable
|
|||
double v = 0;
|
||||
for (int k = 1; k <= 50; k++)
|
||||
{
|
||||
v += (Math.Pow(-1, k) / k) * Math.Sin(frequency * 2 * Math.PI * k * x)
|
||||
/ 4 + 0.5;
|
||||
v += (Math.Pow(-1, k) / k) * Math.Sin(frequency * 2 * Math.PI * k * x);
|
||||
}
|
||||
return -v;
|
||||
}
|
||||
|
||||
public static byte[] GenerateSawtoothWave(double frequency, double time, double volume = 1d)
|
||||
{
|
||||
var amplitude = 128 * volume;
|
||||
var timeStep = 1d / SampleRate;
|
||||
frequency /= 2;
|
||||
|
||||
var buffer = new byte[(int)(SampleRate * time)];
|
||||
var ctime = 0d;
|
||||
for (int i = 0; i < buffer.Length; i++)
|
||||
{
|
||||
//var x = ctime * frequency - Math.Floor(ctime * frequency + 0.5);
|
||||
var x = GetSawtoothPoint(frequency, ctime);
|
||||
buffer[i] = (byte)(amplitude * x);
|
||||
ctime += timeStep;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public static byte[] GenerateNoiseWave(double time, double volume = 1d)
|
||||
{
|
||||
var amplitude = 128 * volume;
|
||||
var timeStep = 1d / SampleRate;
|
||||
|
||||
var buffer = new byte[(int)(SampleRate * time)];
|
||||
var ctime = 0d;
|
||||
for (int i = 0; i < buffer.Length; i++)
|
||||
{
|
||||
buffer[i] = (byte)rng.Next(0, (int)amplitude);
|
||||
ctime += timeStep;
|
||||
}
|
||||
return buffer;
|
||||
return -(2 / Math.PI) * v;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
|
|
@ -3,6 +3,7 @@ using KeraLua;
|
|||
using Microsoft.Xna.Framework.Audio;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using static Capy64.Core.Audio;
|
||||
|
||||
namespace Capy64.Runtime.Libraries;
|
||||
|
||||
|
@ -144,6 +145,8 @@ public class Audio : IPlugin
|
|||
var volume = L.OptNumber(3, 1);
|
||||
volume = Math.Clamp(volume, 0, 1);
|
||||
|
||||
var timespan = TimeSpan.FromSeconds(time);
|
||||
|
||||
var form = L.CheckOption(4, "sine", new string[]
|
||||
{
|
||||
"sine",
|
||||
|
@ -154,16 +157,7 @@ public class Audio : IPlugin
|
|||
null,
|
||||
});
|
||||
|
||||
|
||||
var buffer = form switch
|
||||
{
|
||||
0 => Core.Audio.GenerateSineWave(freq, time, volume),
|
||||
1 => Core.Audio.GenerateSquareWave(freq, time, volume),
|
||||
2 => Core.Audio.GenerateTriangleWave(freq, time, volume),
|
||||
3 => Core.Audio.GenerateSawtoothWave(freq, time, volume),
|
||||
4 => Core.Audio.GenerateNoiseWave(time, volume),
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
var buffer = _game.Audio.GenerateWave((Waveform)form, freq, timespan);
|
||||
|
||||
try
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue