| @@ -22,6 +22,7 @@ plugins: dgl | |||
| $(MAKE) all -C plugins/MidiThrough | |||
| $(MAKE) all -C plugins/Parameters | |||
| $(MAKE) all -C plugins/States | |||
| $(MAKE) all -C plugins/Super_Saw | |||
| ifneq ($(CROSS_COMPILING),true) | |||
| gen: plugins dpf/utils/lv2_ttl_generator | |||
| @@ -0,0 +1,11 @@ | |||
| #ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED | |||
| #define DISTRHO_PLUGIN_INFO_H_INCLUDED | |||
| #define DISTRHO_PLUGIN_NAME "Super Saw" | |||
| #define DISTRHO_PLUGIN_URI "https://github.com/cranixx/Super_Saw_DPF" | |||
| #define DISTRHO_PLUGIN_NUM_INPUTS 1 | |||
| #define DISTRHO_PLUGIN_NUM_OUTPUTS 1 | |||
| #define DISTRHO_PLUGIN_IS_SYNTH 1 | |||
| #endif // DISTRHO_PLUGIN_INFO_H_INCLUDED | |||
| @@ -0,0 +1,61 @@ | |||
| #!/usr/bin/make -f | |||
| # Makefile for DISTRHO Plugins # | |||
| # ---------------------------- # | |||
| # Created by falkTX | |||
| # | |||
| # -------------------------------------------------------------- | |||
| # Project name, used for binaries | |||
| NAME = Super_Saw | |||
| # -------------------------------------------------------------- | |||
| # Files to build | |||
| OBJS_DSP = \ | |||
| SuperSaw.cpp.o | |||
| #OBJS_UI = \ | |||
| # InfoExampleUI.cpp.o | |||
| # -------------------------------------------------------------- | |||
| # Do some magic | |||
| include ../Makefile.mk | |||
| # -------------------------------------------------------------- | |||
| # Enable all possible plugin types | |||
| ifeq ($(HAVE_DGL),true) | |||
| ifeq ($(HAVE_JACK),true) | |||
| TARGETS += jack | |||
| endif | |||
| endif | |||
| ifeq ($(HAVE_DGL),true) | |||
| TARGETS += lv2_sep | |||
| else | |||
| TARGETS += lv2_dsp | |||
| endif | |||
| TARGETS += vst | |||
| ADA: | |||
| gnat make -fPIC blep | |||
| gnat bind -n blep | |||
| gnat make -fPIC super_saw | |||
| gnat bind -n super_saw | |||
| gnat make -fPIC b~super_saw | |||
| gnat bind -n b~super_saw | |||
| gnat make -fPIC polyphony | |||
| gnat bind -n polyphony | |||
| gnat make -fPIC b~polyphony | |||
| gnat bind -n b~polyphony | |||
| #BASE_FLAGS += super_saw.o b~super_saw.o -lgnat -lgnarl -lgmem | |||
| BASE_FLAGS += super_saw.o polyphony.o b~polyphony.o blep.o -lgnat -lgnarl -lgmem -ggdb | |||
| BASE_FLAGS += -L/usr/lib/gcc/x86_64-redhat-linux/7/adalib | |||
| all: ADA $(TARGETS) | |||
| # -------------------------------------------------------------- | |||
| @@ -0,0 +1,168 @@ | |||
| #include "DistrhoPlugin.hpp" | |||
| #include <math.h> | |||
| extern "C" void adainit(void); | |||
| extern "C" void adafinal(void); | |||
| extern "C" void Add_Note(float); | |||
| extern "C" void Remove_Note(float); | |||
| extern "C" float Super_Saw(float,float,float,float,float); | |||
| extern "C" float Compute_Polyphony(float,float,float,float); | |||
| START_NAMESPACE_DISTRHO | |||
| class SuperSaw : public Plugin | |||
| { | |||
| public: | |||
| SuperSaw() : Plugin(2,0,0){ | |||
| adainit(); | |||
| } | |||
| ~SuperSaw() { | |||
| adafinal(); | |||
| } | |||
| protected: | |||
| const char* getLabel() const override | |||
| { | |||
| return "Super Saw"; | |||
| } | |||
| const char* getDescription() const override | |||
| { | |||
| return "Roland JP-8000 Super Saw emulator"; | |||
| } | |||
| const char* getMaker() const override | |||
| { | |||
| return "Cranix"; | |||
| } | |||
| /** | |||
| Get the plugin homepage. | |||
| */ | |||
| const char* getHomePage() const override | |||
| { | |||
| return "http://example.org/Super_Saw"; | |||
| } | |||
| /** | |||
| Get the plugin license name (a single line of text). | |||
| For commercial plugins this should return some short copyright information. | |||
| */ | |||
| const char* getLicense() const override | |||
| { | |||
| return "GPL"; | |||
| } | |||
| /** | |||
| Get the plugin version, in hexadecimal. | |||
| */ | |||
| uint32_t getVersion() const override | |||
| { | |||
| return d_version(1, 0, 0); | |||
| } | |||
| /** | |||
| Get the plugin unique Id. | |||
| This value is used by LADSPA, DSSI and VST plugin formats. | |||
| */ | |||
| int64_t getUniqueId() const override | |||
| { | |||
| return d_cconst('d', 'N', 'f', 'o'); | |||
| } | |||
| void setParameterValue(uint32_t index, float value) override | |||
| { | |||
| if (index == 0) { | |||
| detune = value; | |||
| } else if (index == 1) { | |||
| mix = value; | |||
| } | |||
| } | |||
| float getParameterValue(uint32_t index) const override | |||
| { | |||
| if (index == 0) { | |||
| return detune; | |||
| } else if (index == 1) { | |||
| return mix; | |||
| } | |||
| } | |||
| void initParameter(uint32_t index, Parameter& parameter) override { | |||
| if (index == 0) { /*Detune*/ | |||
| parameter.hints = kParameterIsAutomable; | |||
| parameter.name = "Detune"; | |||
| parameter.symbol = "detune"; | |||
| parameter.ranges.min = 0.0f; | |||
| parameter.ranges.max = 0.9f; | |||
| parameter.ranges.def = 0.5f; | |||
| } else if (index == 1) { /*Mix*/ | |||
| parameter.hints = kParameterIsAutomable; | |||
| parameter.name = "Mix"; | |||
| parameter.symbol = "mix"; | |||
| parameter.ranges.min = 0.0f; | |||
| parameter.ranges.max = 0.9f; | |||
| parameter.ranges.def = 0.5f; | |||
| } | |||
| } | |||
| void run(const float** inputs, float** outputs, uint32_t frames, const MidiEvent* midiEvents, | |||
| uint32_t midiEventCount) override { | |||
| const uint8_t* data; | |||
| uint8_t status; | |||
| uint8_t note; | |||
| float frequency; | |||
| uint32_t framesDone=0; | |||
| uint32_t curEventIndex=0; | |||
| while (framesDone < frames) { | |||
| while (curEventIndex < midiEventCount && framesDone == midiEvents[curEventIndex].frame) { | |||
| if ( midiEvents[curEventIndex].size > MidiEvent::kDataSize ) | |||
| continue; | |||
| data=midiEvents[curEventIndex].data; | |||
| status=data[0]&0xFF; | |||
| if ( ! ( ( status == 0x80 || status == 0x90))) { | |||
| curEventIndex++; | |||
| continue; | |||
| } | |||
| note=data[1]; | |||
| if (status == 0x90) { | |||
| frequency=pow(2.0,(note-57.0)/12.0)*440.0; | |||
| Add_Note(frequency); | |||
| } else if (status == 0x80) { | |||
| // frequency = 0.0; | |||
| frequency=pow(2.0,(note-57.0)/12.0)*440.0; | |||
| Remove_Note(frequency); | |||
| } | |||
| curEventIndex++; | |||
| } | |||
| //outputs[0][framesDone]=sin(phase*frequency/44100.0*2.0*3.14); | |||
| //outputs[0][framesDone]=sin(phase*frequency/44100.0*2.0*3.14); | |||
| outputs[0][framesDone]=Compute_Polyphony(phase,detune,mix,getSampleRate()); | |||
| phase++; | |||
| framesDone++; | |||
| } | |||
| /*data=midiEvents[0].data; | |||
| status=data[0]&0xFF; | |||
| if (status == 0x90){ | |||
| note=data[1]; | |||
| frequency=pow(2.0,(note-57.0)/12.0)*440.0; | |||
| for (i=0;i<frames;i++){ | |||
| outputs[0][i] = sin(phase*2.0*3.14*frequency); | |||
| phase++; | |||
| } | |||
| }*/ | |||
| } //run | |||
| private: | |||
| float phase=0; | |||
| float detune; | |||
| float mix; | |||
| }; | |||
| Plugin* createPlugin() | |||
| { | |||
| return new SuperSaw(); | |||
| } | |||
| END_NAMESPACE_DISTRHO | |||
| @@ -0,0 +1,36 @@ | |||
| package body Blep is | |||
| function BLEP_Saw(Phase : Float; Pitch : Float) return Float is | |||
| T : Float := modulo(Phase,1.0); | |||
| begin | |||
| return Naive_Saw(Phase, Pitch)+T-(T*T/2.0)-0.5; | |||
| end BLEP_Saw; | |||
| function Naive_Saw(Phase : Float; Frequency: Float) return Float is | |||
| begin | |||
| return Modulo((Phase*Frequency),1.0); | |||
| end Naive_Saw; | |||
| function modulo (Dividend : Float; Divisor : Float) return Float is | |||
| Fraction : Float; | |||
| Int_Part : Integer; | |||
| begin | |||
| Int_Part := Integer(Dividend); | |||
| Fraction := Dividend - Float(Int_Part); | |||
| return Float((Int_Part mod Integer(Divisor))) + Fraction; | |||
| end modulo; | |||
| function Sinc (Phase : Float) return Float is | |||
| begin | |||
| if Phase = 0.0 then | |||
| return 1.0; | |||
| else | |||
| return Sin(Phase)/Phase; | |||
| end if; | |||
| end Sinc; | |||
| function Hamming (N : Float; Size : Float) return Float is | |||
| begin | |||
| return 0.54 - 0.46*Cos(2.0*Pi*N/(Size - 1.0)); | |||
| end Hamming; | |||
| end Blep; | |||
| @@ -0,0 +1,14 @@ | |||
| with Ada.Numerics; | |||
| use Ada.Numerics; | |||
| with Ada.Numerics.Elementary_Functions; | |||
| use Ada.Numerics.Elementary_Functions; | |||
| package Blep is | |||
| function BLEP_Saw(Phase : Float; Pitch : Float) return Float; | |||
| private | |||
| function Naive_Saw(Phase : Float; Frequency : Float) return Float; | |||
| function modulo (Dividend : Float; Divisor : Float) return Float; | |||
| function Sinc (Phase : Float) return Float; | |||
| function Hamming (N : Float; Size : Float) return Float; | |||
| end Blep; | |||
| @@ -0,0 +1,52 @@ | |||
| with Interfaces.C; | |||
| use Interfaces.C; | |||
| with Ada.Numerics.Generic_Elementary_Functions; | |||
| with Super_Saw; | |||
| package body Polyphony is | |||
| procedure Add_Note (Pitch : C_Float) is | |||
| begin | |||
| if Note_Count <= Voices then | |||
| for I in Notes'Range loop | |||
| if Notes(I) = 0.0 then | |||
| Notes(I) := Float(Pitch); | |||
| Note_Count := Note_Count + 1; | |||
| exit; | |||
| end if; | |||
| end loop; | |||
| end if; | |||
| end Add_Note; | |||
| procedure Remove_Note (Pitch : C_Float) is | |||
| begin | |||
| if Note_Count > 0 then | |||
| for I in Notes'Range loop | |||
| if Notes(I) = Float(Pitch) then | |||
| Notes(I) := 0.0; | |||
| Note_Count := Note_Count - 1; | |||
| exit; | |||
| end if; | |||
| end loop; | |||
| end if; | |||
| end Remove_Note; | |||
| function Compute_Polyphony (Time : C_Float; | |||
| Detune : C_Float; Mix : C_Float; | |||
| Sample_Rate : C_Float) return C_Float is | |||
| package Float_Functions is new Ada.Numerics.Generic_Elementary_Functions (Float); | |||
| Sample : C_Float := 0.0; | |||
| begin | |||
| for I in Notes'Range loop | |||
| if Notes(I) /= 0.0 then | |||
| -- Compensate for changes in volume by dividing output by logarithm of frequency | |||
| Sample := Sample + Super_Saw.Super_Saw(Time => Time, Pitch => C_Float(Notes(I)), | |||
| Detune => Detune, Mix => Mix, | |||
| Sample_Rate => Sample_Rate)/C_Float(Float_Functions.Log(Notes(I)*30.0,10.0)); | |||
| end if; | |||
| end loop; | |||
| return Sample; | |||
| end Compute_Polyphony; | |||
| end Polyphony; | |||
| @@ -0,0 +1,20 @@ | |||
| with Interfaces.C; | |||
| use Interfaces.C; | |||
| package Polyphony is | |||
| type Note_Array_Type is array (1..4) of Float; | |||
| Notes : Note_Array_Type := (others => 0.0); | |||
| Note_Count : Natural := 0; | |||
| Voices : constant := 4; | |||
| procedure Add_Note (Pitch : C_Float) | |||
| with Post => Note_Count <= Voices and Note_Count >= 0; | |||
| procedure Remove_Note (Pitch : C_Float) | |||
| with Post => Note_Count <= Voices and Note_Count >= 0; | |||
| function Compute_Polyphony (Time : C_Float; Detune : C_Float; Mix : C_Float; | |||
| Sample_Rate : C_Float) return C_Float; | |||
| pragma Export(CPP,Add_Note,"Add_Note"); | |||
| pragma Export(CPP,Remove_Note,"Remove_Note"); | |||
| pragma Export(CPP,Compute_Polyphony,"Compute_Polyphony"); | |||
| end Polyphony; | |||
| @@ -0,0 +1,58 @@ | |||
| with Interfaces.C; | |||
| use Interfaces.C; | |||
| with Ada.Numerics; | |||
| use Ada.Numerics; | |||
| with Ada.Numerics.Elementary_Functions; | |||
| use Ada.Numerics.Elementary_Functions; | |||
| with Blep; | |||
| 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)*Interfaces.C.C_Float(0.1); | |||
| end Super_Saw; | |||
| function Saw(Time : Float; Pitch : Float; Sample_Rate : Float) return Float is | |||
| begin | |||
| return Blep.BLEP_Saw(Time,Pitch/Sample_Rate); | |||
| 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; | |||
| @@ -0,0 +1,19 @@ | |||
| with Interfaces.C; | |||
| use Interfaces.C; | |||
| package Super_Saw is | |||
| type Mix_Level_Type is record | |||
| Master : Float; | |||
| Slave : Float; | |||
| end record; | |||
| type Offset_Array_Type is array (1..3) of Float; | |||
| function Saw(Time : Float; Pitch : Float; Sample_Rate : Float) return Float; | |||
| function Compute_Detune(Amount : Float) return Float; | |||
| function Compute_Mix(Level : Float) return Mix_Level_Type; | |||
| 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; | |||
| pragma Export(CPP,Super_Saw,"Super_Saw"); | |||
| end Super_Saw; | |||