summaryrefslogtreecommitdiffstats
path: root/super_saw.adb
diff options
context:
space:
mode:
Diffstat (limited to 'super_saw.adb')
-rw-r--r--super_saw.adb75
1 files changed, 75 insertions, 0 deletions
diff --git a/super_saw.adb b/super_saw.adb
new file mode 100644
index 0000000..7498e03
--- /dev/null
+++ b/super_saw.adb
@@ -0,0 +1,75 @@
+with Interfaces.C;
+use Interfaces.C;
+
+with Ada.Numerics;
+use Ada.Numerics;
+
+with Ada.Numerics.Elementary_Functions;
+use Ada.Numerics.Elementary_Functions;
+
+package body Super_Saw is
+ function Super_Saw(Time : Interfaces.C.C_Float; Pitch : Interfaces.C.C_Float;
+ Detune : Interfaces.C.C_Float; Mix : Interfaces.C.C_Float;
+ Sample_Rate : Interfaces.C.C_Float)
+ return Interfaces.C.C_Float is
+ Offsets : Offset_Array_Type := (0.01952356,0.06288439,0.11002313);
+ Sample : Float := 0.0;
+ Mix_Level : Mix_Level_Type := Compute_Mix(Float(Mix));
+ begin
+ -- Main oscillator
+ Sample := Sample + Saw(Float(Time),Float(Pitch), Float(Sample_Rate))*Mix_Level.Master;
+
+ -- 3 oscillators of higher pitch than main
+ Higher_Oscillators:for D in 1 .. 3 loop
+ Sample := Sample + Saw(Float(Time),Float(Pitch)*(1.0+Offsets(D)*Compute_Detune(Float(Detune))),
+ Float(Sample_Rate))*Mix_Level.Slave;
+ end loop Higher_Oscillators;
+
+ -- 3 oscillators of lower pitch than main
+ Lower_Oscillators:for D in 1 .. 3 loop
+ Sample := Sample + Saw(Float(Time),Float(Pitch)*(1.0+Offsets(D)*Compute_Detune(Float(Detune))),
+ Float(Sample_Rate))*Mix_Level.Slave;
+ end loop Lower_Oscillators;
+ return Interfaces.C.C_FLoat(Sample);
+ end Super_Saw;
+
+ function Saw(Time : Float; Pitch : Float; Sample_Rate : Float) return Float is
+ Number_Of_Harmonics : Integer := 0;
+ Sample : Float := 0.0;
+ begin
+ while 2.0*Pi*Pitch*Float(Number_Of_Harmonics) < Sample_Rate/2.0 loop
+ Number_Of_Harmonics := Number_Of_Harmonics + 1;
+ end loop;
+
+ for I in 1 .. Number_Of_Harmonics loop
+ Sample := Sample + ((((1.0)**Float(I))*Sin(Float(I)*((2.0*Pi*Pitch)/Sample_Rate)*Time)));
+ end loop;
+ Sample := 0.5 - Sample/Pi;
+
+ -- Add a few extra sines to simulate aliasing above fundamental frequency of main oscillator
+ Simulate_Aliasing:for I in 1 .. Number_Of_Harmonics loop
+ if (0.5-2.0*Pi*Float(I)*Pitch/Sample_Rate) >= (2.0*Pi*Pitch)/Sample_Rate then
+ Sample := Sample + Sin((0.5-2.0*Pi*Float(I)*Pitch/Sample_Rate)*Time)*0.6;
+ end if;
+ end loop Simulate_Aliasing;
+
+ return Sample;
+ end Saw;
+ function Compute_Detune(Amount : Float) return Float is
+ begin
+ return (10028.7312891634*Amount**11)-(50818.8652045924*Amount**10)
+ +(111363.4808729368*Amount**9)-(138150.6761080548*Amount**8)+
+ (106649.6679158292*Amount**7)-(53046.9642751875*Amount**6)+
+ (17019.9518580080*Amount**5)-(3425.0836591318*Amount**4)+
+ (404.2703938388*Amount**3)-(24.1878824391*Amount**2)+
+ (0.6717417634*Amount)+0.0030115596;
+ end Compute_Detune;
+ function Compute_Mix(Level : Float) return Mix_Level_Type is
+ Mix_Level : Mix_Level_Type;
+ begin
+ Mix_Level.Master := -0.55366*Level + 0.99785;
+ Mix_Level.Slave := -0.73764*Level**2 + 1.2841*Level + 0.044372;
+ return Mix_Level;
+ end Compute_Mix;
+end Super_Saw;
+