From 2d40755674b409ce35ff9ab22f356ae8e6fbc50a Mon Sep 17 00:00:00 2001 From: Cranix Date: Thu, 17 May 2018 20:06:21 +0200 Subject: [PATCH] Added Super Saw plugin --- Makefile | 1 + plugins/Super_Saw/DistrhoPluginInfo.h | 11 ++ plugins/Super_Saw/Makefile | 61 ++++++++++ plugins/Super_Saw/SuperSaw.cpp | 168 ++++++++++++++++++++++++++ plugins/Super_Saw/blep.adb | 36 ++++++ plugins/Super_Saw/blep.ads | 14 +++ plugins/Super_Saw/polyphony.adb | 52 ++++++++ plugins/Super_Saw/polyphony.ads | 20 +++ plugins/Super_Saw/super_saw.adb | 58 +++++++++ plugins/Super_Saw/super_saw.ads | 19 +++ 10 files changed, 440 insertions(+) create mode 100644 plugins/Super_Saw/DistrhoPluginInfo.h create mode 100644 plugins/Super_Saw/Makefile create mode 100644 plugins/Super_Saw/SuperSaw.cpp create mode 100644 plugins/Super_Saw/blep.adb create mode 100644 plugins/Super_Saw/blep.ads create mode 100644 plugins/Super_Saw/polyphony.adb create mode 100644 plugins/Super_Saw/polyphony.ads create mode 100644 plugins/Super_Saw/super_saw.adb create mode 100644 plugins/Super_Saw/super_saw.ads diff --git a/Makefile b/Makefile index b9857d5..651a49b 100644 --- a/Makefile +++ b/Makefile @@ -21,6 +21,7 @@ plugins: libs $(MAKE) all -C plugins/Meters $(MAKE) all -C plugins/Parameters $(MAKE) all -C plugins/States + $(MAKE) all -C plugins/Super_Saw gen: plugins dpf/utils/lv2_ttl_generator @$(CURDIR)/dpf/utils/generate-ttl.sh diff --git a/plugins/Super_Saw/DistrhoPluginInfo.h b/plugins/Super_Saw/DistrhoPluginInfo.h new file mode 100644 index 0000000..5b68131 --- /dev/null +++ b/plugins/Super_Saw/DistrhoPluginInfo.h @@ -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 + diff --git a/plugins/Super_Saw/Makefile b/plugins/Super_Saw/Makefile new file mode 100644 index 0000000..89894c7 --- /dev/null +++ b/plugins/Super_Saw/Makefile @@ -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) + +# -------------------------------------------------------------- diff --git a/plugins/Super_Saw/SuperSaw.cpp b/plugins/Super_Saw/SuperSaw.cpp new file mode 100644 index 0000000..34fb6d2 --- /dev/null +++ b/plugins/Super_Saw/SuperSaw.cpp @@ -0,0 +1,168 @@ +#include "DistrhoPlugin.hpp" +#include +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 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; + diff --git a/plugins/Super_Saw/polyphony.ads b/plugins/Super_Saw/polyphony.ads new file mode 100644 index 0000000..ed9fd75 --- /dev/null +++ b/plugins/Super_Saw/polyphony.ads @@ -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; + diff --git a/plugins/Super_Saw/super_saw.adb b/plugins/Super_Saw/super_saw.adb new file mode 100644 index 0000000..c972b89 --- /dev/null +++ b/plugins/Super_Saw/super_saw.adb @@ -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; + diff --git a/plugins/Super_Saw/super_saw.ads b/plugins/Super_Saw/super_saw.ads new file mode 100644 index 0000000..676c0bf --- /dev/null +++ b/plugins/Super_Saw/super_saw.ads @@ -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; +