├── figure.gif ├── screenshot.png ├── .gitmodules ├── source ├── BLITSineHardSync_guids.h ├── BLITSineHardSync_controller.h ├── BLITSineHardSync_processor.h ├── BLITSineHardSync_controller.cpp ├── BLITSineHardSync_entry.cpp ├── BLITSineHardSync_oscillator.h ├── BLITSineHardSync_processor.cpp └── BLITSineHardSync_oscillator.cpp ├── CMakeLists.txt ├── LICENSE ├── README.md └── test_plot.py /figure.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fukuroder/BLIT-based_sinewave_hardsync/HEAD/figure.gif -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fukuroder/BLIT-based_sinewave_hardsync/HEAD/screenshot.png -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "remez_approx"] 2 | path = remez_approx 3 | url = https://github.com/fukuroder/remez_approx 4 | -------------------------------------------------------------------------------- /source/BLITSineHardSync_guids.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BLITSineHardSync_guids.h 3 | * 4 | * Copyright (c) 2017, fukuroda (https://github.com/fukuroder) 5 | * Released under the MIT license 6 | */ 7 | 8 | #pragma once 9 | #include "pluginterfaces/base/funknown.h" 10 | 11 | using namespace Steinberg; 12 | 13 | // processor GUID 14 | // {64CC4FEA-349E-4274-BCAC-35EFD201941F} 15 | static const FUID BLITSineHardSyncProcessorID(0x64CC4FEA, 0x349E4274, 0xBCAC35EF, 0xD201941F); 16 | 17 | // controller GUID 18 | // {447E3A16-175E-43ED-B7A6-378A74E4CE63} 19 | static const FUID BLITSineHardSyncControllerID(0x447E3A16, 0x175E43ED, 0xB7A6378A, 0x74E4CE63); 20 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | set(blit_based_sinewave_hardsync_sources 3 | source/BLITSineHardSync_processor.cpp 4 | source/BLITSineHardSync_processor.h 5 | source/BLITSineHardSync_controller.cpp 6 | source/BLITSineHardSync_controller.h 7 | source/BLITSineHardSync_entry.cpp 8 | source/BLITSineHardSync_guids.h 9 | source/BLITSineHardSync_oscillator.cpp 10 | source/BLITSineHardSync_oscillator.h 11 | remez_approx/remez_approx.h 12 | ) 13 | 14 | set(target blit_based_sinewave_hardsync) 15 | smtg_add_vst3plugin(${target} ${blit_based_sinewave_hardsync_sources}) 16 | set_target_properties(${target} PROPERTIES ${SDK_IDE_PLUGIN_EXAMPLES_FOLDER}) 17 | target_link_libraries(${target} PRIVATE sdk) 18 | -------------------------------------------------------------------------------- /source/BLITSineHardSync_controller.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BLITSineHardSync_controller.h 3 | * 4 | * Copyright (c) 2017, fukuroda (https://github.com/fukuroder) 5 | * Released under the MIT license 6 | */ 7 | 8 | #pragma once 9 | #include "public.sdk/source/vst/vsteditcontroller.h" 10 | 11 | using namespace Steinberg; 12 | using namespace Steinberg::Vst; 13 | namespace MyVst { 14 | 15 | // controller 16 | class BLITSineHardSync_controller : public EditController 17 | { 18 | // constructor(private) 19 | BLITSineHardSync_controller(); 20 | 21 | public: 22 | // create 23 | static FUnknown* create(void* context); 24 | 25 | // from EditController class 26 | virtual tresult PLUGIN_API initialize(FUnknown* context); 27 | }; 28 | 29 | // 30 | class BLITSineHardSync_SlaveParameter : public Parameter 31 | { 32 | public: 33 | BLITSineHardSync_SlaveParameter(); 34 | virtual void toString(ParamValue normValue, String128 string)const; 35 | }; 36 | } // namespace 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 fukuroda 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /source/BLITSineHardSync_processor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BLITSaw_processor.h 3 | * 4 | * Copyright (c) 2017, fukuroda (https://github.com/fukuroder) 5 | * Released under the MIT license 6 | */ 7 | 8 | #pragma once 9 | #include "public.sdk/source/vst/vstaudioeffect.h" 10 | #include "BLITSineHardSync_oscillator.h" 11 | #include 12 | 13 | using namespace Steinberg; 14 | using namespace Steinberg::Vst; 15 | namespace MyVst { 16 | // 17 | class BLITSineHardSync_processor : public AudioEffect 18 | { 19 | // constructor(private) 20 | BLITSineHardSync_processor(); 21 | 22 | public: 23 | // create 24 | static FUnknown* create(void* context); 25 | 26 | // from AudioEffect class 27 | virtual tresult PLUGIN_API initialize(FUnknown* context); 28 | virtual tresult PLUGIN_API setBusArrangements( 29 | SpeakerArrangement* inputs, 30 | int32 numIns, 31 | SpeakerArrangement* outputs, 32 | int32 numOuts); 33 | virtual tresult PLUGIN_API process(ProcessData& data); 34 | 35 | protected: 36 | 37 | // 38 | enum 39 | { 40 | Slave 41 | }; 42 | 43 | // 44 | BLITSineHardSync_oscillator blit; 45 | }; 46 | } // namespace 47 | -------------------------------------------------------------------------------- /source/BLITSineHardSync_controller.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * BLITSineHardSync_controller.cpp 3 | * 4 | * Copyright (c) 2017, fukuroda (https://github.com/fukuroder) 5 | * Released under the MIT license 6 | */ 7 | 8 | #include "BLITSineHardSync_controller.h" 9 | #include "pluginterfaces/base/ibstream.h" 10 | #include 11 | 12 | namespace MyVst { 13 | // 14 | BLITSineHardSync_controller::BLITSineHardSync_controller() 15 | { 16 | } 17 | 18 | // 19 | FUnknown* BLITSineHardSync_controller::create(void* context) 20 | { 21 | return (IEditController*)new BLITSineHardSync_controller(); 22 | } 23 | 24 | // 25 | tresult PLUGIN_API BLITSineHardSync_controller::initialize(FUnknown* context) 26 | { 27 | tresult result = EditController::initialize(context); 28 | if (result != kResultOk) 29 | { 30 | return result; 31 | } 32 | 33 | parameters.addParameter(new BLITSineHardSync_SlaveParameter()); 34 | 35 | return kResultOk; 36 | } 37 | 38 | // 39 | BLITSineHardSync_SlaveParameter::BLITSineHardSync_SlaveParameter() 40 | :Parameter(L"Slave", 0, L"", 0.2) 41 | { 42 | } 43 | 44 | void BLITSineHardSync_SlaveParameter::toString(ParamValue normValue, String128 string)const 45 | { 46 | ::swprintf_s(string, 128, L"%.3f", 1.0 + normValue); 47 | } 48 | } // namespace 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### BLIT-based sinewave hardsync(vst3/VC++2019) 2 | 3 | ![Screenshot](https://raw.github.com/fukuroder/BLIT-based_sinewave_hardsync/master/screenshot.png) 4 | 5 | - - - 6 | 7 | ### Algorithm 8 | This waveform is constructed with additive synthesis and BLIT synthesis. 9 | 10 | ![Figure1](https://raw.github.com/fukuroder/BLIT-based_sinewave_hardsync/master/figure.gif) 11 | 12 | ```python 13 | import math 14 | 15 | # initialize... 16 | sample_rate = 44100.0 # sample rate 17 | 18 | leak = 0.995 # [0.99, 1.0) (used for leaky integrator) 19 | 20 | slave = 1.2 # [1.0, 2.0] (slave_freq = master_freq * slave) 21 | 22 | # set frequency... 23 | master_freq = 440.0 # master frequency 24 | 25 | n = int(sample_rate/2/master_freq) # Nyquist limit 26 | dt = 2*math.pi*master_freq/sample_rate # delta t 27 | b1 = math.sin(math.pi*slave)/math.pi*(-1/(1+slave)-1/(1-slave)+2) # Fourier coefficient for sin(2*PI*1*t) 28 | b2 = math.sin(math.pi*slave)/math.pi*(-1/(2+slave)-1/(2-slave)+1) # Fourier coefficient for sin(2*PI*2*t) 29 | b3 = -math.sin(math.pi*slave)/math.pi # used for BLIT section 30 | 31 | # for each sample... 32 | t = -math.pi # current position 33 | blit_sum = 0.0 # current value for BLIT section 34 | for _ in range(1000): 35 | # output 36 | print(b1*math.sin(t) + b2*math.sin(2*t) + b3*blit_sum) 37 | 38 | # update position 39 | t += dt 40 | 41 | # update BLIT (dividing by zero is not considered!) 42 | blit_sum = leak*blit_sum + (math.sin((n+0.5)*t)/math.sin(0.5*t)-1.0)*dt 43 | ``` 44 | -------------------------------------------------------------------------------- /source/BLITSineHardSync_entry.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * BLITSineHardSync_entry.cpp 3 | * 4 | * Copyright (c) 2017, fukuroda (https://github.com/fukuroder) 5 | * Released under the MIT license 6 | */ 7 | 8 | #include "BLITSineHardSync_processor.h" 9 | #include "BLITSineHardSync_controller.h" 10 | #include "BLITSineHardSync_guids.h" 11 | #include "public.sdk/source/main/pluginfactory.h" 12 | 13 | // 14 | bool InitModule() 15 | { 16 | // nothing to do 17 | return true; 18 | } 19 | 20 | // 21 | bool DeinitModule() 22 | { 23 | // nothing to do 24 | return true; 25 | } 26 | 27 | using namespace Steinberg::Vst; 28 | 29 | // define factory 30 | BEGIN_FACTORY_DEF( 31 | "fukuroda", // vendor 32 | "https://github.com/fukuroder", // url 33 | "mailto:fukuroder@live.jp") // e-mail 34 | 35 | // register processor 36 | DEF_CLASS2( 37 | INLINE_UID_FROM_FUID(BLITSineHardSyncProcessorID), // processor's GUID 38 | PClassInfo::kManyInstances, // ? 39 | kVstAudioEffectClass, // category 40 | "BLITSineHardSync", // plug-in name 41 | kDistributable, // Component flag 42 | PlugType::kInstrumentSynth, // sub category 43 | "1.0.0.000", // plug-in version 44 | kVstVersionString, // VSTSDK version 45 | MyVst::BLITSineHardSync_processor::create) // create method 46 | 47 | // register controller 48 | DEF_CLASS2( 49 | INLINE_UID_FROM_FUID(BLITSineHardSyncControllerID), // controller's GUID 50 | PClassInfo::kManyInstances, // ? 51 | kVstComponentControllerClass, // category 52 | "BLITSineHardSync Controller", // plug-in name 53 | 0, // N/A 54 | "", // N/A 55 | "1.0.0.000", // plug-in version 56 | kVstVersionString, // VSTSDK version 57 | MyVst::BLITSineHardSync_controller::create) // create method 58 | END_FACTORY 59 | -------------------------------------------------------------------------------- /source/BLITSineHardSync_oscillator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * BLITSineHardSync_oscillator.h 3 | * 4 | * Copyright (c) 2017, fukuroda (https://github.com/fukuroder) 5 | * Released under the MIT license 6 | */ 7 | 8 | #pragma once 9 | #include 10 | #include "pluginterfaces/vst/ivstevents.h" 11 | 12 | using namespace Steinberg; 13 | using namespace Steinberg::Vst; 14 | namespace MyVst { 15 | // 16 | class BLITSineHardSync_oscillator_note 17 | { 18 | public: 19 | BLITSineHardSync_oscillator_note(); 20 | 21 | // ADSR 22 | enum ADSR 23 | { 24 | // 25 | Off, 26 | 27 | // 28 | On, 29 | }; 30 | 31 | // 32 | ADSR envelope; 33 | 34 | // 35 | int32_t t; 36 | 37 | // 38 | int32 sampleOffset; 39 | 40 | // 41 | double blit; 42 | 43 | // 44 | double value; 45 | 46 | // 47 | int32_t n; 48 | 49 | // 50 | int32_t dt; 51 | 52 | // 53 | int32_t note_id; 54 | 55 | // 56 | double velocity; 57 | }; 58 | 59 | // 60 | class BLITSineHardSync_oscillator 61 | { 62 | public: 63 | // constructor 64 | BLITSineHardSync_oscillator(); 65 | 66 | // 67 | void setSlave(double value); 68 | 69 | // 70 | void trigger(const NoteOnEvent& noteOn, int32 sampleOffset, double srate); 71 | 72 | // 73 | void release(const NoteOffEvent& noteOff); 74 | 75 | // 76 | bool is_silent(); 77 | 78 | // 79 | double render(); 80 | 81 | // 82 | void next(); 83 | 84 | protected: 85 | 86 | // 87 | static const int _note_no_center = 69; 88 | 89 | // 90 | std::array _notes; 91 | 92 | // 93 | double _Slave; 94 | 95 | // 96 | const double _Leak; 97 | 98 | // Fourier coefficient for sin(2*PI*1*t) 99 | double _b1; 100 | 101 | // Fourier coefficient for sin(2*PI*2*t) 102 | double _b2; 103 | 104 | // used for BLIT section 105 | double _b3; 106 | 107 | // 108 | double BLIT(int32_t t, int n)const; 109 | }; 110 | } // namespace 111 | -------------------------------------------------------------------------------- /test_plot.py: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------ 2 | # test_plot.py 3 | # 4 | # Copyright (c) 2016, fukuroda (https://github.com/fukuroder) 5 | # Released under the MIT license 6 | #------------------------------------------------------------ 7 | 8 | # import 9 | import math 10 | import matplotlib.pyplot as plt 11 | 12 | # initialize... 13 | sample_rate = 44100.0 # sample rate 14 | 15 | leak = 0.995 # [0.99, 1.0) 16 | # used for leaky integrator 17 | 18 | slave = 1.2 # [1.0, 2.0] 19 | # (slave_freq = master_freq * slave) 20 | 21 | # set frequency... 22 | master_freq = 440.0 # master frequency 23 | 24 | n = int(sample_rate/2/master_freq) # Nyquist limit 25 | dt = 2*math.pi*master_freq/sample_rate # delta t 26 | b1 = math.sin(math.pi*slave)/math.pi*(-1/(1+slave)-1/(1-slave)+2) # Fourier coefficient for sin(2*PI*1*t) 27 | b2 = math.sin(math.pi*slave)/math.pi*(-1/(2+slave)-1/(2-slave)+1) # Fourier coefficient for sin(2*PI*2*t) 28 | b3 = -math.sin(math.pi*slave)/math.pi # used for BLIT section 29 | 30 | # for each sample... 31 | t = -math.pi # current position 32 | blit_sum = 0.0 # current value for BLIT section 33 | v1 = [] 34 | v2 = [] 35 | v3 = [] 36 | for _ in range(400): 37 | # output 38 | v1.append(b1*math.sin(t) + b2*math.sin(2*t)) 39 | v2.append(b3*blit_sum) 40 | v3.append(b1*math.sin(t) + b2*math.sin(2*t) + b3*blit_sum) 41 | 42 | # update position 43 | t += dt 44 | 45 | # update BLIT (dividing by zero is not considered!) 46 | blit_sum = leak*blit_sum + (math.sin((n+0.5)*t)/math.sin(0.5*t)-1.0)*dt 47 | 48 | # Additive synthesis section(k=1...2) 49 | p1 = plt.subplot(311) 50 | plt.plot(v1) 51 | plt.ylim([-1.5,1.5]) 52 | plt.grid() 53 | plt.setp(p1.get_xticklabels(), visible=False) 54 | plt.setp(p1.get_yticklabels(), visible=False) 55 | plt.title('Additive synthesis(k=1...2)', fontsize=10) 56 | 57 | # BLIT synthesis section(k=3...N) 58 | p2 = plt.subplot(312) 59 | plt.plot(v2) 60 | plt.ylim([-1.5,1.5]) 61 | plt.grid() 62 | plt.setp(p2.get_xticklabels(), visible=False) 63 | plt.setp(p2.get_yticklabels(), visible=False) 64 | plt.title('BLIT_saw', fontsize=10) 65 | 66 | # Additive + BLIT 67 | p3 = plt.subplot(313) 68 | plt.plot(v3) 69 | plt.ylim([-1.5,1.5]) 70 | plt.grid() 71 | plt.setp(p3.get_xticklabels(), visible=False) 72 | plt.setp(p3.get_yticklabels(), visible=False) 73 | plt.title('Additive + BLIT_saw', fontsize=10) 74 | 75 | plt.show() 76 | -------------------------------------------------------------------------------- /source/BLITSineHardSync_processor.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * BLITSineHardSync_processor.cpp 3 | * 4 | * Copyright (c) 2017, fukuroda (https://github.com/fukuroder) 5 | * Released under the MIT license 6 | */ 7 | 8 | #include "BLITSineHardSync_processor.h" 9 | #include "BLITSineHardSync_guids.h" 10 | #include "pluginterfaces/vst/ivstparameterchanges.h" 11 | #include 12 | 13 | namespace MyVst { 14 | // 15 | BLITSineHardSync_processor::BLITSineHardSync_processor() 16 | { 17 | setControllerClass(BLITSineHardSyncControllerID); 18 | } 19 | 20 | // 21 | FUnknown* BLITSineHardSync_processor::create(void* context) 22 | { 23 | return (IAudioProcessor*)new BLITSineHardSync_processor(); 24 | } 25 | 26 | // 27 | tresult PLUGIN_API BLITSineHardSync_processor::initialize(FUnknown* context) 28 | { 29 | // base class initialization 30 | tresult result = AudioEffect::initialize(context); 31 | if (result != kResultOk) 32 | { 33 | return result; 34 | } 35 | 36 | // set bus 37 | addAudioOutput(STR16("Stereo Out"), SpeakerArr::kStereo); 38 | 39 | return kResultOk; 40 | } 41 | 42 | // 43 | tresult PLUGIN_API BLITSineHardSync_processor::setBusArrangements( 44 | SpeakerArrangement* inputs, 45 | int32 numIns, 46 | SpeakerArrangement* outputs, 47 | int32 numOuts 48 | ) { 49 | if (numIns == 0 && numOuts == 1 && outputs[0] == SpeakerArr::kStereo) 50 | { 51 | return AudioEffect::setBusArrangements(inputs, numIns, outputs, numOuts); 52 | } 53 | return kResultFalse; 54 | } 55 | 56 | // 57 | tresult PLUGIN_API BLITSineHardSync_processor::process(ProcessData& data) 58 | { 59 | //------------------- 60 | // update parameters 61 | //------------------- 62 | if (data.inputParameterChanges) 63 | { 64 | int32 numParamsChanged = data.inputParameterChanges->getParameterCount(); 65 | for (int32 ii = 0; ii < numParamsChanged; ii++) 66 | { 67 | IParamValueQueue* paramQueue = data.inputParameterChanges->getParameterData(ii); 68 | if (paramQueue) 69 | { 70 | int32 offsetSamples; 71 | double value; 72 | // 73 | if (paramQueue->getPoint(paramQueue->getPointCount() - 1, offsetSamples, value) == kResultTrue) 74 | { 75 | ParamID id = paramQueue->getParameterId(); 76 | if (id == Slave) 77 | { 78 | // -> [1.0, 2.0] 79 | double Slave = 1.0 + value; 80 | blit.setSlave(Slave); 81 | } 82 | } 83 | } 84 | } 85 | } 86 | 87 | //---------------- 88 | // process events 89 | //---------------- 90 | if (data.inputEvents) 91 | { 92 | int nEventCount = data.inputEvents->getEventCount(); 93 | 94 | for (int ii = 0; ii < nEventCount; ii++) 95 | { 96 | Event e; 97 | tresult result = data.inputEvents->getEvent(ii, e); 98 | if (result != kResultOk)continue; 99 | 100 | if (e.type == Event::kNoteOnEvent) 101 | { 102 | blit.trigger(e.noteOn, e.sampleOffset, processSetup.sampleRate); 103 | } 104 | else if (e.type == Event::kNoteOffEvent) 105 | { 106 | blit.release(e.noteOff); 107 | } 108 | } 109 | } 110 | 111 | if (blit.is_silent()) 112 | { 113 | return kResultOk; 114 | } 115 | 116 | // 117 | if (data.numInputs == 0 && data.numOutputs == 1 && data.outputs[0].numChannels == 2) 118 | { 119 | Sample32** out = data.outputs[0].channelBuffers32; 120 | const int32 sampleFrames = data.numSamples; 121 | for (int ii = 0; ii < sampleFrames; ii++) 122 | { 123 | out[0][ii] = out[1][ii] = blit.render(); 124 | blit.next(); 125 | } 126 | } 127 | return kResultOk; 128 | } 129 | } // namespace 130 | -------------------------------------------------------------------------------- /source/BLITSineHardSync_oscillator.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * BLITSineHardSync_oscillator.cpp 3 | * 4 | * Copyright (c) 2017, fukuroda (https://github.com/fukuroder) 5 | * Released under the MIT license 6 | */ 7 | 8 | #define _USE_MATH_DEFINES 9 | #include 10 | #include 11 | #include "BLITSineHardSync_oscillator.h" 12 | #include "../remez_approx/remez_approx.h" 13 | 14 | namespace MyVst { 15 | 16 | // constructor 17 | BLITSineHardSync_oscillator_note::BLITSineHardSync_oscillator_note() 18 | :envelope(ADSR::Off) 19 | , t(0) 20 | , sampleOffset(0) 21 | , blit(0.0) 22 | , value(0.0) 23 | , n(0) 24 | , dt(0) 25 | , note_id(0) 26 | , velocity(0.0) 27 | { 28 | } 29 | 30 | // 31 | void BLITSineHardSync_oscillator::trigger(const NoteOnEvent& noteOn, int32 sampleOffset, double srate) 32 | { 33 | // 34 | auto available_note = std::find_if( 35 | _notes.begin(), 36 | _notes.end(), 37 | [](const BLITSineHardSync_oscillator_note& n) {return n.envelope == BLITSineHardSync_oscillator_note::Off; }); 38 | 39 | if (available_note != _notes.end()) { 40 | available_note->note_id = noteOn.noteId; 41 | available_note->velocity = noteOn.velocity; 42 | available_note->envelope = BLITSineHardSync_oscillator_note::On; 43 | 44 | // 45 | double freq = 440.0 * (::pow(2.0, (static_cast(noteOn.pitch) - 69) / 12.0)); 46 | available_note->n = static_cast(srate / 2.0 / freq); 47 | available_note->dt = static_cast(0xFFFFFFFFU / srate * freq); 48 | available_note->blit = 0.0; 49 | available_note->t = INT32_MIN; 50 | available_note->value = 0.0; 51 | } 52 | } 53 | 54 | // 55 | void BLITSineHardSync_oscillator::release(const NoteOffEvent& noteOff) 56 | { 57 | const int32 note_id = noteOff.noteId; 58 | auto target_note = std::find_if( 59 | _notes.begin(), 60 | _notes.end(), 61 | [note_id](const BLITSineHardSync_oscillator_note& n) {return n.note_id == note_id; }); 62 | 63 | if (target_note != _notes.end()) { 64 | // 65 | target_note->envelope = BLITSineHardSync_oscillator_note::Off; 66 | } 67 | } 68 | 69 | bool BLITSineHardSync_oscillator::is_silent() 70 | { 71 | return std::all_of( 72 | _notes.begin(), 73 | _notes.end(), 74 | [](const BLITSineHardSync_oscillator_note& n) {return n.envelope == BLITSineHardSync_oscillator_note::Off; }); 75 | } 76 | 77 | // constructor 78 | BLITSineHardSync_oscillator::BLITSineHardSync_oscillator() 79 | :_Slave(0.0) 80 | , _Leak(0.995) 81 | , _b1(0.0) 82 | , _b2(0.0) 83 | , _b3(0.0) 84 | { 85 | setSlave(1.2); 86 | } 87 | 88 | // set slave parameter 89 | void BLITSineHardSync_oscillator::setSlave(double value) 90 | { 91 | _Slave = value; 92 | if (value < 1.0 + 1.0e-12) 93 | { 94 | _b1 = -1.0; 95 | _b2 = 0.0; 96 | _b3 = 0.0; 97 | } 98 | else if (value < 2.0 - 1.0e-12) 99 | { 100 | _b1 = ::sin(M_PI * value) / M_PI * (-1 / (1 + value) - 1 / (1 - value) + 2); 101 | _b2 = ::sin(M_PI * value) / M_PI * (-1 / (2 + value) - 1 / (2 - value) + 1); 102 | _b3 = -::sin(M_PI * value) / 0xFFFFFFFFU; 103 | } 104 | else 105 | { 106 | _b1 = 0.0; 107 | _b2 = 1.0; 108 | _b3 = 0.0; 109 | } 110 | } 111 | 112 | // 113 | double BLITSineHardSync_oscillator::BLIT(int32_t t, int n)const 114 | { 115 | double den = remez_sin_int32(t / 2); 116 | double num = remez_sin_int32(t / 2 + n * t); 117 | 118 | if (den < -1.0e-12 || 1.0e-12 < den) 119 | { 120 | return 2.0 * num / den; 121 | } 122 | else 123 | { 124 | // apply L'Hopital's rule 125 | return 2.0 * (2.0 * n + 1.0); 126 | } 127 | } 128 | 129 | // 130 | double BLITSineHardSync_oscillator::render() 131 | { 132 | double value = 0.0; 133 | for (auto& note : _notes) 134 | { 135 | if (note.envelope == BLITSineHardSync_oscillator_note::On) { 136 | // add 137 | value += note.value * note.velocity; 138 | } 139 | } 140 | return value; 141 | } 142 | 143 | // 144 | void BLITSineHardSync_oscillator::next() 145 | { 146 | for (auto& note : _notes) 147 | { 148 | // update t 149 | note.t += note.dt; 150 | 151 | if (note.n >= 3) 152 | { 153 | // update BLIT section(n=3 -> Nyquist limit) 154 | note.blit = note.blit * _Leak + (BLIT(note.t, note.n) - 2.0) * note.dt; 155 | 156 | // synthesize value 157 | note.value = _b1 * remez_sin_int32(note.t) 158 | + _b2 * remez_sin_int32(2 * note.t) 159 | + _b3 * note.blit; 160 | } 161 | else if (note.n == 2) 162 | { 163 | // reset BLIT section 164 | note.blit = 0.0; 165 | 166 | // synthesize value 167 | note.value = _b1 * remez_sin_int32(note.t) 168 | + _b2 * remez_sin_int32(2 * note.t); 169 | } 170 | else 171 | { 172 | // reset BLIT section 173 | note.blit = 0.0; 174 | 175 | // synthesize value 176 | note.value = _b1 * remez_sin_int32(note.t); 177 | } 178 | } 179 | } 180 | 181 | } // namespace --------------------------------------------------------------------------------