diff --git a/.gitmodules b/.gitmodules index 09ed00d..9b1f263 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "circle-stdlib"] path = circle-stdlib url = https://github.com/smuehlst/circle-stdlib +[submodule "Synth_Dexed"] + path = Synth_Dexed + url = https://codeberg.org/dcoredump/Synth_Dexed.git diff --git a/Synth_Dexed b/Synth_Dexed new file mode 160000 index 0000000..ffeef83 --- /dev/null +++ b/Synth_Dexed @@ -0,0 +1 @@ +Subproject commit ffeef830ab1f8e99a709a5fdf08fc25f0b855ca0 diff --git a/src/Makefile b/src/Makefile index 286691a..ddc064d 100644 --- a/src/Makefile +++ b/src/Makefile @@ -3,16 +3,14 @@ # CIRCLE_STDLIB_DIR = ../circle-stdlib -MSFA_DIR = msfa +SYNTH_DEXED_DIR = ../Synth_Dexed/src -OBJS = main.o kernel.o miniorgan.o \ - $(MSFA_DIR)/dx7note.o $(MSFA_DIR)/env.o $(MSFA_DIR)/exp2.o $(MSFA_DIR)/fm_core.o \ - $(MSFA_DIR)/fm_op_kernel.o $(MSFA_DIR)/freqlut.o $(MSFA_DIR)/lfo.o \ - $(MSFA_DIR)/pitchenv.o $(MSFA_DIR)/sin.o $(MSFA_DIR)/tuning.o +OBJS = main.o kernel.o miniorgan.o \ + $(SYNTH_DEXED_DIR)/synth_dexed.o \ -INCLUDE += -I $(MSFA_DIR) -I tuning-library +INCLUDE += -I $(SYNTH_DEXED_DIR) -I tuning-library -EXTRACLEAN = $(MSFA_DIR)/*.o $(MSFA_DIR)/*.d +EXTRACLEAN = $(SYNTH_DEXED_DIR)/*.o $(SYNTH_DEXED_DIR)/*.d include ./Rules.mk diff --git a/src/msfa/aligned_buf.h b/src/msfa/aligned_buf.h deleted file mode 100644 index 8f7c5b6..0000000 --- a/src/msfa/aligned_buf.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2013 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// A convenient wrapper for buffers with alignment constraints - -// Note that if we were on C++11, we'd use aligned_storage or somesuch. - -#ifndef __ALIGNED_BUF_H -#define __ALIGNED_BUF_H - -#include - -template -class AlignedBuf { - public: - T *get() { - return (T *)((((intptr_t)storage_) + alignment - 1) & -alignment); - } - private: - unsigned char storage_[size * sizeof(T) + alignment]; -}; - -#endif // __ALIGNED_BUF_H diff --git a/src/msfa/controllers.h b/src/msfa/controllers.h deleted file mode 100644 index 99de232..0000000 --- a/src/msfa/controllers.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2013 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __CONTROLLERS_H -#define __CONTROLLERS_H - -#include "synth.h" -#include "../Dexed.h" -#include -#include - -#ifdef _WIN32 -#define snprintf _snprintf -#endif - -// State of MIDI controllers -const int kControllerPitch = 128; -const int kControllerPitchRangeUp = 129; -const int kControllerPitchStep = 130; -const int kControllerPitchRangeDn = 131; - -class FmCore; - -struct FmMod { - int range; - bool pitch; - bool amp; - bool eg; - - FmMod() { - range = 0; - pitch = false; - amp = false; - eg = false; - } - - void parseConfig(const char *cfg) { - int r = 0, p = 0, a = 0, e = 0; - sscanf(cfg, "%d %d %d %d", &r, &p, &a, &e); - - range = r < 0 || r > 127 ? 0 : r; - pitch = p != 0; - amp = a != 0; - eg = e != 0; - } - - void setConfig(char *cfg) { - snprintf(cfg, 13, "%d %d %d %d", range, pitch, amp, eg); - } -}; - -class Controllers { - void applyMod(int cc, FmMod &mod) { - float range = 0.01 * mod.range; - int total = cc * range; - if ( mod.amp ) - amp_mod = max(amp_mod, total); - - if ( mod.pitch ) - pitch_mod = max(pitch_mod, total); - - if ( mod.eg ) - eg_mod = max(eg_mod, total); - } - -public: - int values_[132]; - - char opSwitch[7]; - - int amp_mod; - int pitch_mod; - int eg_mod; - - int aftertouch_cc; - int breath_cc; - int foot_cc; - int modwheel_cc; - - int masterTune; - - bool transpose12AsScale = true; - - // MPE configuration. FIXME - make this switchable - bool mpeEnabled = true; - int mpePitchBendRange = 24; - - FmMod wheel; - FmMod foot; - FmMod breath; - FmMod at; - - Controllers() { - amp_mod = 0; - pitch_mod = 0; - eg_mod = 0; - strcpy(opSwitch, "111111"); - } - - void refresh() { - amp_mod = 0; - pitch_mod = 0; - eg_mod = 0; - - applyMod(modwheel_cc, wheel); - applyMod(breath_cc, breath); - applyMod(foot_cc, foot); - applyMod(aftertouch_cc, at); - - if ( ! ((wheel.eg || foot.eg) || (breath.eg || at.eg)) ) - eg_mod = 127; - - } - - FmCore *core; -}; - -#endif // __CONTROLLERS_H - diff --git a/src/msfa/dx7note.cc b/src/msfa/dx7note.cc deleted file mode 100644 index 4b68633..0000000 --- a/src/msfa/dx7note.cc +++ /dev/null @@ -1,358 +0,0 @@ -/* - * Copyright 2016-2017 Pascal Gauthier. - * Copyright 2012 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include "synth.h" -#include "freqlut.h" -#include "exp2.h" -#include "controllers.h" -#include "dx7note.h" -#include -#include - -const int FEEDBACK_BITDEPTH = 8; - -const int32_t coarsemul[] = { - -16777216, 0, 16777216, 26591258, 33554432, 38955489, 43368474, 47099600, - 50331648, 53182516, 55732705, 58039632, 60145690, 62083076, 63876816, - 65546747, 67108864, 68576247, 69959732, 71268397, 72509921, 73690858, - 74816848, 75892776, 76922906, 77910978, 78860292, 79773775, 80654032, - 81503396, 82323963, 83117622 -}; - -int32_t Dx7Note::osc_freq(int midinote, int mode, int coarse, int fine, int detune) { - // TODO: pitch randomization - int32_t logfreq; - if (mode == 0) { - logfreq = tuning_state_->midinote_to_logfreq(midinote); - - // could use more precision, closer enough for now. those numbers comes from my DX7 - double detuneRatio = 0.0209 * exp(-0.396 * (((float)logfreq)/(1<<24))) / 7; - logfreq += detuneRatio * logfreq * (detune - 7); - - logfreq += coarsemul[coarse & 31]; - if (fine) { - // (1 << 24) / log(2) - logfreq += (int32_t)floor(24204406.323123 * log(1 + 0.01 * fine) + 0.5); - } - - // // This was measured at 7.213Hz per count at 9600Hz, but the exact - // // value is somewhat dependent on midinote. Close enough for now. - // //logfreq += 12606 * (detune -7); - } else { - // ((1 << 24) * log(10) / log(2) * .01) << 3 - logfreq = (4458616 * ((coarse & 3) * 100 + fine)) >> 3; - logfreq += detune > 7 ? 13457 * (detune - 7) : 0; - } - return logfreq; -} - -const uint8_t velocity_data[64] = { - 0, 70, 86, 97, 106, 114, 121, 126, 132, 138, 142, 148, 152, 156, 160, 163, - 166, 170, 173, 174, 178, 181, 184, 186, 189, 190, 194, 196, 198, 200, 202, - 205, 206, 209, 211, 214, 216, 218, 220, 222, 224, 225, 227, 229, 230, 232, - 233, 235, 237, 238, 240, 241, 242, 243, 244, 246, 246, 248, 249, 250, 251, - 252, 253, 254 -}; - -// See "velocity" section of notes. Returns velocity delta in microsteps. -int ScaleVelocity(int velocity, int sensitivity) { - int clamped_vel = max(0, min(127, velocity)); - int vel_value = velocity_data[clamped_vel >> 1] - 239; - int scaled_vel = ((sensitivity * vel_value + 7) >> 3) << 4; - return scaled_vel; -} - -int ScaleRate(int midinote, int sensitivity) { - int x = min(31, max(0, midinote / 3 - 7)); - int qratedelta = (sensitivity * x) >> 3; -#ifdef SUPER_PRECISE - int rem = x & 7; - if (sensitivity == 3 && rem == 3) { - qratedelta -= 1; - } else if (sensitivity == 7 && rem > 0 && rem < 4) { - qratedelta += 1; - } -#endif - return qratedelta; -} - -const uint8_t exp_scale_data[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 14, 16, 19, 23, 27, 33, 39, 47, 56, 66, - 80, 94, 110, 126, 142, 158, 174, 190, 206, 222, 238, 250 -}; - -int ScaleCurve(int group, int depth, int curve) { - int scale; - if (curve == 0 || curve == 3) { - // linear - scale = (group * depth * 329) >> 12; - } else { - // exponential - int n_scale_data = sizeof(exp_scale_data); - int raw_exp = exp_scale_data[min(group, n_scale_data - 1)]; - scale = (raw_exp * depth * 329) >> 15; - } - if (curve < 2) { - scale = -scale; - } - return scale; -} - -int ScaleLevel(int midinote, int break_pt, int left_depth, int right_depth, - int left_curve, int right_curve) { - int offset = midinote - break_pt - 17; - if (offset >= 0) { - return ScaleCurve((offset+1) / 3, right_depth, right_curve); - } else { - return ScaleCurve(-(offset-1) / 3, left_depth, left_curve); - } -} - -static const uint8_t pitchmodsenstab[] = { - 0, 10, 20, 33, 55, 92, 153, 255 -}; - -// 0, 66, 109, 255 -static const uint32_t ampmodsenstab[] = { - 0, 4342338, 7171437, 16777216 -}; - -Dx7Note::Dx7Note(std::shared_ptr ts) : tuning_state_(ts) { - for(int op=0;op<6;op++) { - params_[op].phase = 0; - params_[op].gain_out = 0; - } -} - -void Dx7Note::init(const uint8_t patch[156], int midinote, int velocity) { - int rates[4]; - int levels[4]; - playingMidiNote = midinote; - for (int op = 0; op < 6; op++) { - int off = op * 21; - for (int i = 0; i < 4; i++) { - rates[i] = patch[off + i]; - levels[i] = patch[off + 4 + i]; - } - int outlevel = patch[off + 16]; - outlevel = Env::scaleoutlevel(outlevel); - int level_scaling = ScaleLevel(midinote, patch[off + 8], patch[off + 9], - patch[off + 10], patch[off + 11], patch[off + 12]); - outlevel += level_scaling; - outlevel = min(127, outlevel); - outlevel = outlevel << 5; - outlevel += ScaleVelocity(velocity, patch[off + 15]); - outlevel = max(0, outlevel); - int rate_scaling = ScaleRate(midinote, patch[off + 13]); - env_[op].init(rates, levels, outlevel, rate_scaling); - - int mode = patch[off + 17]; - int coarse = patch[off + 18]; - int fine = patch[off + 19]; - int detune = patch[off + 20]; - int32_t freq = osc_freq(midinote, mode, coarse, fine, detune); - opMode[op] = mode; - basepitch_[op] = freq; - ampmodsens_[op] = ampmodsenstab[patch[off + 14] & 3]; - } - for (int i = 0; i < 4; i++) { - rates[i] = patch[126 + i]; - levels[i] = patch[130 + i]; - } - pitchenv_.set(rates, levels); - algorithm_ = patch[134]; - int feedback = patch[135]; - fb_shift_ = feedback != 0 ? FEEDBACK_BITDEPTH - feedback : 16; - pitchmoddepth_ = (patch[139] * 165) >> 6; - pitchmodsens_ = pitchmodsenstab[patch[143] & 7]; - ampmoddepth_ = (patch[140] * 165) >> 6; - - // MPE default valeus - mpePitchBend = 8192; - mpeTimbre = 0; - mpePressure = 0; -} - -void Dx7Note::compute(int32_t *buf, int32_t lfo_val, int32_t lfo_delay, const Controllers *ctrls) { - // ==== PITCH ==== - uint32_t pmd = pitchmoddepth_ * lfo_delay; // Q32 - int32_t senslfo = pitchmodsens_ * (lfo_val - (1 << 23)); - int32_t pmod_1 = (((int64_t) pmd) * (int64_t) senslfo) >> 39; - pmod_1 = abs(pmod_1); - int32_t pmod_2 = (int32_t)(((int64_t)ctrls->pitch_mod * (int64_t)senslfo) >> 14); - pmod_2 = abs(pmod_2); - int32_t pitch_mod = max(pmod_1, pmod_2); - pitch_mod = pitchenv_.getsample() + (pitch_mod * (senslfo < 0 ? -1 : 1)); - - // ---- PITCH BEND ---- - int pitchbend = ctrls->values_[kControllerPitch]; - int32_t pb = (pitchbend - 0x2000); - if (pb != 0) { - if (ctrls->values_[kControllerPitchStep] == 0) { - if( pb >= 0 ) - pb = ((float) (pb << 11)) * ((float) ctrls->values_[kControllerPitchRangeUp]) / 12.0; - else - pb = ((float) (pb << 11)) * ((float) ctrls->values_[kControllerPitchRangeDn]) / 12.0; - } else { - int stp = 12 / ctrls->values_[kControllerPitchStep]; - pb = pb * stp / 8191; - pb = (pb * (8191 / stp)) << 11; - } - } - - if( ctrls->mpeEnabled ) - { - int d = ((float)( (mpePitchBend-0x2000) << 11 )) * ctrls->mpePitchBendRange / 12.0; - // std::cout << mpePitchBend << " " << 0x2000 << " " << d << std::endl; - pb += d; - } - - if( ! tuning_state_->is_standard_tuning() && pb != 0 ) - { - // If we have a scale we want PB to be in scale space so we sort of need to - // unwind the combinations above and re-interpolate - - float notesTuned = ( pb >> 11 ) * 12.0 / 8192; // How many steps you tuned - int floorNote = std::floor(notesTuned); - float frac = notesTuned - floorNote; - float targetLog = tuning_state_->midinote_to_logfreq(playingMidiNote + floorNote) * ( 1.0 - frac ) + - tuning_state_->midinote_to_logfreq(playingMidiNote + floorNote + 1) * frac; // the interpolated log freq - float newpb = targetLog - tuning_state_->midinote_to_logfreq(playingMidiNote); // and the resulting bend - pb = newpb; - } - - int32_t pitch_base = pb + ctrls->masterTune; - pitch_mod += pitch_base; - - // ==== AMP MOD ==== - lfo_val = (1<<24) - lfo_val; - uint32_t amod_1 = (uint32_t)(((int64_t) ampmoddepth_ * (int64_t) lfo_delay) >> 8); // Q24 :D - amod_1 = (uint32_t)(((int64_t) amod_1 * (int64_t) lfo_val) >> 24); - uint32_t amod_2 = (uint32_t)(((int64_t) ctrls->amp_mod * (int64_t) lfo_val) >> 7); // Q?? :| - uint32_t amd_mod = max(amod_1, amod_2); - - // ==== EG AMP MOD ==== - uint32_t amod_3 = (ctrls->eg_mod+1) << 17; - amd_mod = max((1<<24) - amod_3, amd_mod); - - // ==== OP RENDER ==== - for (int op = 0; op < 6; op++) { - if ( ctrls->opSwitch[op] == '0' ) { - env_[op].getsample(); // advance the envelop even if it is not playing - params_[op].level_in = 0; - } else { - //int32_t gain = pow(2, 10 + level * (1.0 / (1 << 24))); - - if ( opMode[op] ) - params_[op].freq = Freqlut::lookup(basepitch_[op] + pitch_base); - else - params_[op].freq = Freqlut::lookup(basepitch_[op] + pitch_mod); - - int32_t level = env_[op].getsample(); - if (ampmodsens_[op] != 0) { - uint32_t sensamp = (uint32_t)(((uint64_t) amd_mod) * ((uint64_t) ampmodsens_[op]) >> 24); - - // TODO: mehhh.. this needs some real tuning. - uint32_t pt = exp(((float)sensamp)/262144 * 0.07 + 12.2); - uint32_t ldiff = (uint32_t)(((uint64_t)level) * (((uint64_t)pt<<4)) >> 28); - level -= ldiff; - } - params_[op].level_in = level; - } - } - ctrls->core->render(buf, params_, algorithm_, fb_buf_, fb_shift_); -} - -void Dx7Note::keyup() { - for (int op = 0; op < 6; op++) { - env_[op].keydown(false); - } - pitchenv_.keydown(false); -} - -void Dx7Note::update(const uint8_t patch[156], int midinote, int velocity) { - int rates[4]; - int levels[4]; - playingMidiNote = midinote; - for (int op = 0; op < 6; op++) { - int off = op * 21; - int mode = patch[off + 17]; - int coarse = patch[off + 18]; - int fine = patch[off + 19]; - int detune = patch[off + 20]; - basepitch_[op] = osc_freq(midinote, mode, coarse, fine, detune); - ampmodsens_[op] = ampmodsenstab[patch[off + 14] & 3]; - opMode[op] = mode; - - for (int i = 0; i < 4; i++) { - rates[i] = patch[off + i]; - levels[i] = patch[off + 4 + i]; - } - int outlevel = patch[off + 16]; - outlevel = Env::scaleoutlevel(outlevel); - int level_scaling = ScaleLevel(midinote, patch[off + 8], patch[off + 9], - patch[off + 10], patch[off + 11], patch[off + 12]); - outlevel += level_scaling; - outlevel = min(127, outlevel); - outlevel = outlevel << 5; - outlevel += ScaleVelocity(velocity, patch[off + 15]); - outlevel = max(0, outlevel); - int rate_scaling = ScaleRate(midinote, patch[off + 13]); - env_[op].update(rates, levels, outlevel, rate_scaling); - } - algorithm_ = patch[134]; - int feedback = patch[135]; - fb_shift_ = feedback != 0 ? FEEDBACK_BITDEPTH - feedback : 16; - pitchmoddepth_ = (patch[139] * 165) >> 6; - pitchmodsens_ = pitchmodsenstab[patch[143] & 7]; - ampmoddepth_ = (patch[140] * 165) >> 6; -} - -void Dx7Note::peekVoiceStatus(VoiceStatus &status) { - for(int i=0;i<6;i++) { - status.amp[i] = Exp2::lookup(params_[i].level_in - (14 * (1 << 24))); - env_[i].getPosition(&status.ampStep[i]); - } - pitchenv_.getPosition(&status.pitchStep); -} - -/** - * Used in monophonic mode to transfer voice state from different notes - */ -void Dx7Note::transferState(Dx7Note &src) { - for (int i=0;i<6;i++) { - env_[i].transfer(src.env_[i]); - params_[i].gain_out = src.params_[i].gain_out; - params_[i].phase = src.params_[i].phase; - } -} - -void Dx7Note::transferSignal(Dx7Note &src) { - for (int i=0;i<6;i++) { - params_[i].gain_out = src.params_[i].gain_out; - params_[i].phase = src.params_[i].phase; - } -} - -void Dx7Note::oscSync() { - for (int i=0;i<6;i++) { - params_[i].gain_out = 0; - params_[i].phase = 0; - } -} diff --git a/src/msfa/dx7note.h b/src/msfa/dx7note.h deleted file mode 100644 index 6125781..0000000 --- a/src/msfa/dx7note.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2016-2017 Pascal Gauthier. - * Copyright 2012 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SYNTH_DX7NOTE_H_ -#define SYNTH_DX7NOTE_H_ - -// This is the logic to put together a note from the MIDI description -// and run the low-level modules. - -// It will continue to evolve a bit, as note-stealing logic, scaling, -// and real-time control of parameters live here. - -#include "env.h" -#include "pitchenv.h" -#include "fm_core.h" -#include "tuning.h" -#include - -struct VoiceStatus { - uint32_t amp[6]; - char ampStep[6]; - char pitchStep; -}; - -class Dx7Note { -public: - Dx7Note(std::shared_ptr ts); - void init(const uint8_t patch[156], int midinote, int velocity); - - // Note: this _adds_ to the buffer. Interesting question whether it's - // worth it... - void compute(int32_t *buf, int32_t lfo_val, int32_t lfo_delay, - const Controllers *ctrls); - - void keyup(); - - // TODO: some way of indicating end-of-note. Maybe should be a return - // value from the compute method? (Having a count return from keyup - // is also tempting, but if there's a dynamic parameter change after - // keyup, that won't work. - - // PG:add the update - void update(const uint8_t patch[156], int midinote, int velocity); - void peekVoiceStatus(VoiceStatus &status); - void transferState(Dx7Note& src); - void transferSignal(Dx7Note &src); - void oscSync(); - - int32_t osc_freq(int midinote, int mode, int coarse, int fine, int detune); - - std::shared_ptr tuning_state_; - - int mpePitchBend = 8192; - int mpePressure = 0; - int mpeTimbre = 0; - -private: - Env env_[6]; - FmOpParams params_[6]; - PitchEnv pitchenv_; - int32_t basepitch_[6]; - int32_t fb_buf_[2]; - int32_t fb_shift_; - int32_t ampmodsens_[6]; - int32_t opMode[6]; - - uint8_t playingMidiNote; // We need this for scale aware pitch bend - - int ampmoddepth_; - int algorithm_; - int pitchmoddepth_; - int pitchmodsens_; - -}; - -#endif // SYNTH_DX7NOTE_H_ diff --git a/src/msfa/env.cc b/src/msfa/env.cc deleted file mode 100644 index dfc3958..0000000 --- a/src/msfa/env.cc +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright 2017 Pascal Gauthier. - * Copyright 2012 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include "synth.h" -#include "env.h" - -#include "../Dexed.h" -//using namespace std; - -uint32_t Env::sr_multiplier = (1<<24); - -const int levellut[] = { - 0, 5, 9, 13, 17, 20, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 42, 43, 45, 46 -}; - -#ifdef ACCURATE_ENVELOPE -const int statics[] = { - 1764000, 1764000, 1411200, 1411200, 1190700, 1014300, 992250, - 882000, 705600, 705600, 584325, 507150, 502740, 441000, 418950, - 352800, 308700, 286650, 253575, 220500, 220500, 176400, 145530, - 145530, 125685, 110250, 110250, 88200, 88200, 74970, 61740, - 61740, 55125, 48510, 44100, 37485, 31311, 30870, 27562, 27562, - 22050, 18522, 17640, 15435, 14112, 13230, 11025, 9261, 9261, 7717, - 6615, 6615, 5512, 5512, 4410, 3969, 3969, 3439, 2866, 2690, 2249, - 1984, 1896, 1808, 1411, 1367, 1234, 1146, 926, 837, 837, 705, - 573, 573, 529, 441, 441 - // and so on, I stopped measuring after R=76 (needs to be double-checked anyway) -}; -#endif - -void Env::init_sr(double sampleRate) { - sr_multiplier = (44100.0 / sampleRate) * (1<<24); -} - -void Env::init(const int r[4], const int l[4], int ol, int rate_scaling) { - for (int i = 0; i < 4; i++) { - rates_[i] = r[i]; - levels_[i] = l[i]; - } - outlevel_ = ol; - rate_scaling_ = rate_scaling; - level_ = 0; - down_ = true; - advance(0); -} - -int32_t Env::getsample() { -#ifdef ACCURATE_ENVELOPE - if (staticcount_) { - staticcount_ -= N; - if (staticcount_ <= 0) { - staticcount_ = 0; - advance(ix_ + 1); - } - } -#endif - - if (ix_ < 3 || ((ix_ < 4) && !down_)) { - if (staticcount_) { - ; - } - else if (rising_) { - const int jumptarget = 1716; - if (level_ < (jumptarget << 16)) { - level_ = jumptarget << 16; - } - level_ += (((17 << 24) - level_) >> 24) * inc_; - // TODO: should probably be more accurate when inc is large - if (level_ >= targetlevel_) { - level_ = targetlevel_; - advance(ix_ + 1); - } - } - else { // !rising - level_ -= inc_; - if (level_ <= targetlevel_) { - level_ = targetlevel_; - advance(ix_ + 1); - } - } - } - // TODO: this would be a good place to set level to 0 when under threshold - return level_; -} - -void Env::keydown(bool d) { - if (down_ != d) { - down_ = d; - advance(d ? 0 : 3); - } -} - -int Env::scaleoutlevel(int outlevel) { - return outlevel >= 20 ? 28 + outlevel : levellut[outlevel]; -} - -void Env::advance(int newix) { - ix_ = newix; - if (ix_ < 4) { - int newlevel = levels_[ix_]; - int actuallevel = scaleoutlevel(newlevel) >> 1; - actuallevel = (actuallevel << 6) + outlevel_ - 4256; - actuallevel = actuallevel < 16 ? 16 : actuallevel; - // level here is same as Java impl - targetlevel_ = actuallevel << 16; - rising_ = (targetlevel_ > level_); - - // rate - int qrate = (rates_[ix_] * 41) >> 6; - qrate += rate_scaling_; - qrate = min(qrate, 63); - -#ifdef ACCURATE_ENVELOPE - if (targetlevel_ == level_ || (ix_ == 0 && newlevel == 0)) { - // approximate number of samples at 44.100 kHz to achieve the time - // empirically gathered using 2 TF1s, could probably use some double-checking - // and cleanup, but it's pretty close for now. - int staticrate = rates_[ix_]; - staticrate += rate_scaling_; // needs to be checked, as well, but seems correct - staticrate = min(staticrate, 99); - staticcount_ = staticrate < 77 ? statics[staticrate] : 20 * (99 - staticrate); - if (staticrate < 77 && (ix_ == 0 && newlevel == 0)) { - staticcount_ /= 20; // attack is scaled faster - } - staticcount_ = (int)(((int64_t)staticcount_ * (int64_t)sr_multiplier) >> 24); - } - else { - staticcount_ = 0; - } -#endif - inc_ = (4 + (qrate & 3)) << (2 + LG_N + (qrate >> 2)); - // meh, this should be fixed elsewhere - inc_ = (int)(((int64_t)inc_ * (int64_t)sr_multiplier) >> 24); - } -} - -void Env::update(const int r[4], const int l[4], int ol, int rate_scaling) { - for (int i = 0; i < 4; i++) { - rates_[i] = r[i]; - levels_[i] = l[i]; - } - outlevel_ = ol; - rate_scaling_ = rate_scaling; - if ( down_ ) { - // for now we simply reset ourselves at level 3 - int newlevel = levels_[2]; - int actuallevel = scaleoutlevel(newlevel) >> 1; - actuallevel = (actuallevel << 6) - 4256; - actuallevel = actuallevel < 16 ? 16 : actuallevel; - targetlevel_ = actuallevel << 16; - advance(2); - } -} - -void Env::getPosition(char *step) { - *step = ix_; -} - -void Env::transfer(Env &src) { - for(int i=0;i<4;i++) { - rates_[i] = src.rates_[i]; - levels_[i] = src.levels_[i]; - } - outlevel_ = src.outlevel_; - rate_scaling_ = src.rate_scaling_; - level_ = src.level_; - targetlevel_ = src.targetlevel_; - rising_= src.rising_; - ix_ = src.ix_; - down_ = src.down_; -#ifdef ACCURATE_ENVELOPE - staticcount_ = src.staticcount_; -#endif - inc_ = src.inc_; -} - diff --git a/src/msfa/env.h b/src/msfa/env.h deleted file mode 100644 index 9aaf7ec..0000000 --- a/src/msfa/env.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2017 Pascal Gauthier. - * Copyright 2012 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __ENV_H -#define __ENV_H - -#include "synth.h" - -// DX7 envelope generation - -#define ACCURATE_ENVELOPE - -class Env { - public: - - // The rates and levels arrays are calibrated to match the Dx7 parameters - // (ie, value 0..99). The outlevel parameter is calibrated in microsteps - // (ie units of approx .023 dB), with 99 * 32 = nominal full scale. The - // rate_scaling parameter is in qRate units (ie 0..63). - void init(const int rates[4], const int levels[4], int outlevel, - int rate_scaling); - - void update(const int rates[4], const int levels[4], int outlevel, - int rate_scaling); - // Result is in Q24/doubling log format. Also, result is subsampled - // for every N samples. - // A couple more things need to happen for this to be used as a gain - // value. First, the # of outputs scaling needs to be applied. Also, - // modulation. - // Then, of course, log to linear. - int32_t getsample(); - - void keydown(bool down); - static int scaleoutlevel(int outlevel); - void getPosition(char *step); - - static void init_sr(double sample_rate); - void transfer(Env &src); - - private: - - // PG: This code is normalized to 44100, need to put a multiplier - // if we are not using 44100. - static uint32_t sr_multiplier; - - int rates_[4]; - int levels_[4]; - int outlevel_; - int rate_scaling_; - // Level is stored so that 2^24 is one doubling, ie 16 more bits than - // the DX7 itself (fraction is stored in level rather than separate - // counter) - int32_t level_; - int targetlevel_; - bool rising_; - int ix_; - int inc_; -#ifdef ACCURATE_ENVELOPE - int staticcount_; -#endif - - bool down_; - - void advance(int newix); -}; - -#endif // __ENV_H - diff --git a/src/msfa/exp2.cc b/src/msfa/exp2.cc deleted file mode 100644 index 84feb20..0000000 --- a/src/msfa/exp2.cc +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2013 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define _USE_MATH_DEFINES -#include - -#include "synth.h" -#include "exp2.h" - -#include - -#ifdef _MSC_VER -#define exp2(arg) pow(2.0, arg) -#endif - - - -int32_t exp2tab[EXP2_N_SAMPLES << 1]; - -void Exp2::init() { - double inc = exp2(1.0 / EXP2_N_SAMPLES); - double y = 1 << 30; - for (int i = 0; i < EXP2_N_SAMPLES; i++) { - exp2tab[(i << 1) + 1] = (int32_t)floor(y + 0.5); - y *= inc; - } - for (int i = 0; i < EXP2_N_SAMPLES - 1; i++) { - exp2tab[i << 1] = exp2tab[(i << 1) + 3] - exp2tab[(i << 1) + 1]; - } - exp2tab[(EXP2_N_SAMPLES << 1) - 2] = (1U << 31) - exp2tab[(EXP2_N_SAMPLES << 1) - 1]; -} - -int32_t tanhtab[TANH_N_SAMPLES << 1]; - -static double dtanh(double y) { - return 1 - y * y; -} - -void Tanh::init() { - double step = 4.0 / TANH_N_SAMPLES; - double y = 0; - for (int i = 0; i < TANH_N_SAMPLES; i++) { - tanhtab[(i << 1) + 1] = (1 << 24) * y + 0.5; - //printf("%d\n", tanhtab[(i << 1) + 1]); - // Use a basic 4th order Runge-Kutte to compute tanh from its - // differential equation. - double k1 = dtanh(y); - double k2 = dtanh(y + 0.5 * step * k1); - double k3 = dtanh(y + 0.5 * step * k2); - double k4 = dtanh(y + step * k3); - double dy = (step / 6) * (k1 + k4 + 2 * (k2 + k3)); - y += dy; - } - for (int i = 0; i < TANH_N_SAMPLES - 1; i++) { - tanhtab[i << 1] = tanhtab[(i << 1) + 3] - tanhtab[(i << 1) + 1]; - } - int32_t lasty = (1 << 24) * y + 0.5; - tanhtab[(TANH_N_SAMPLES << 1) - 2] = lasty - tanhtab[(TANH_N_SAMPLES << 1) - 1]; -} diff --git a/src/msfa/exp2.h b/src/msfa/exp2.h deleted file mode 100644 index 016ca33..0000000 --- a/src/msfa/exp2.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -class Exp2 { - public: - Exp2(); - - static void init(); - - // Q24 in, Q24 out - static int32_t lookup(int32_t x); -}; - -#define EXP2_LG_N_SAMPLES 10 -#define EXP2_N_SAMPLES (1 << EXP2_LG_N_SAMPLES) - -#define EXP2_INLINE - -extern int32_t exp2tab[EXP2_N_SAMPLES << 1]; - -#ifdef EXP2_INLINE -inline -int32_t Exp2::lookup(int32_t x) { - const int SHIFT = 24 - EXP2_LG_N_SAMPLES; - int lowbits = x & ((1 << SHIFT) - 1); - int x_int = (x >> (SHIFT - 1)) & ((EXP2_N_SAMPLES - 1) << 1); - int dy = exp2tab[x_int]; - int y0 = exp2tab[x_int + 1]; - - int y = y0 + (((int64_t)dy * (int64_t)lowbits) >> SHIFT); - return y >> (6 - (x >> 24)); -} -#endif - -class Tanh { - public: - static void init(); - - // Q24 in, Q24 out - static int32_t lookup(int32_t x); -}; - -#define TANH_LG_N_SAMPLES 10 -#define TANH_N_SAMPLES (1 << TANH_LG_N_SAMPLES) - -extern int32_t tanhtab[TANH_N_SAMPLES << 1]; - -inline -int32_t Tanh::lookup(int32_t x) { - int32_t signum = x >> 31; - x ^= signum; - if (x >= (4 << 24)) { - if (x >= (17 << 23)) { - return signum ^ (1 << 24); - } - int32_t sx = ((int64_t)-48408812 * (int64_t)x) >> 24; - return signum ^ ((1 << 24) - 2 * Exp2::lookup(sx)); - } else { - const int SHIFT = 26 - TANH_LG_N_SAMPLES; - int lowbits = x & ((1 << SHIFT) - 1); - int x_int = (x >> (SHIFT - 1)) & ((TANH_N_SAMPLES - 1) << 1); - int dy = tanhtab[x_int]; - int y0 = tanhtab[x_int + 1]; - int y = y0 + (((int64_t)dy * (int64_t)lowbits) >> SHIFT); - return y ^ signum; - } -} diff --git a/src/msfa/fm_core.cc b/src/msfa/fm_core.cc deleted file mode 100644 index 8bfd9eb..0000000 --- a/src/msfa/fm_core.cc +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifdef VERBOSE -#include -#endif - -#include "synth.h" -#include "exp2.h" -#include "fm_op_kernel.h" -#include "fm_core.h" - - -//using namespace std; - -const FmAlgorithm FmCore::algorithms[32] = { - { { 0xc1, 0x11, 0x11, 0x14, 0x01, 0x14 } }, // 1 - { { 0x01, 0x11, 0x11, 0x14, 0xc1, 0x14 } }, // 2 - { { 0xc1, 0x11, 0x14, 0x01, 0x11, 0x14 } }, // 3 - { { 0xc1, 0x11, 0x94, 0x01, 0x11, 0x14 } }, // 4 - { { 0xc1, 0x14, 0x01, 0x14, 0x01, 0x14 } }, // 5 - { { 0xc1, 0x94, 0x01, 0x14, 0x01, 0x14 } }, // 6 - { { 0xc1, 0x11, 0x05, 0x14, 0x01, 0x14 } }, // 7 - { { 0x01, 0x11, 0xc5, 0x14, 0x01, 0x14 } }, // 8 - { { 0x01, 0x11, 0x05, 0x14, 0xc1, 0x14 } }, // 9 - { { 0x01, 0x05, 0x14, 0xc1, 0x11, 0x14 } }, // 10 - { { 0xc1, 0x05, 0x14, 0x01, 0x11, 0x14 } }, // 11 - { { 0x01, 0x05, 0x05, 0x14, 0xc1, 0x14 } }, // 12 - { { 0xc1, 0x05, 0x05, 0x14, 0x01, 0x14 } }, // 13 - { { 0xc1, 0x05, 0x11, 0x14, 0x01, 0x14 } }, // 14 - { { 0x01, 0x05, 0x11, 0x14, 0xc1, 0x14 } }, // 15 - { { 0xc1, 0x11, 0x02, 0x25, 0x05, 0x14 } }, // 16 - { { 0x01, 0x11, 0x02, 0x25, 0xc5, 0x14 } }, // 17 - { { 0x01, 0x11, 0x11, 0xc5, 0x05, 0x14 } }, // 18 - { { 0xc1, 0x14, 0x14, 0x01, 0x11, 0x14 } }, // 19 - { { 0x01, 0x05, 0x14, 0xc1, 0x14, 0x14 } }, // 20 - { { 0x01, 0x14, 0x14, 0xc1, 0x14, 0x14 } }, // 21 - { { 0xc1, 0x14, 0x14, 0x14, 0x01, 0x14 } }, // 22 - { { 0xc1, 0x14, 0x14, 0x01, 0x14, 0x04 } }, // 23 - { { 0xc1, 0x14, 0x14, 0x14, 0x04, 0x04 } }, // 24 - { { 0xc1, 0x14, 0x14, 0x04, 0x04, 0x04 } }, // 25 - { { 0xc1, 0x05, 0x14, 0x01, 0x14, 0x04 } }, // 26 - { { 0x01, 0x05, 0x14, 0xc1, 0x14, 0x04 } }, // 27 - { { 0x04, 0xc1, 0x11, 0x14, 0x01, 0x14 } }, // 28 - { { 0xc1, 0x14, 0x01, 0x14, 0x04, 0x04 } }, // 29 - { { 0x04, 0xc1, 0x11, 0x14, 0x04, 0x04 } }, // 30 - { { 0xc1, 0x14, 0x04, 0x04, 0x04, 0x04 } }, // 31 - { { 0xc4, 0x04, 0x04, 0x04, 0x04, 0x04 } }, // 32 -}; - -int n_out(const FmAlgorithm &alg) { - int count = 0; - for (int i = 0; i < 6; i++) { - if ((alg.ops[i] & 7) == OUT_BUS_ADD) count++; - } - return count; -} - -void FmCore::dump() { -#ifdef VERBOSE - for (int i = 0; i < 32; i++) { - cout << (i + 1) << ":"; - const FmAlgorithm &alg = algorithms[i]; - for (int j = 0; j < 6; j++) { - int flags = alg.ops[j]; - cout << " "; - if (flags & FB_IN) cout << "["; - cout << (flags & IN_BUS_ONE ? "1" : flags & IN_BUS_TWO ? "2" : "0") << "->"; - cout << (flags & OUT_BUS_ONE ? "1" : flags & OUT_BUS_TWO ? "2" : "0"); - if (flags & OUT_BUS_ADD) cout << "+"; - //cout << alg.ops[j].in << "->" << alg.ops[j].out; - if (flags & FB_OUT) cout << "]"; - } - cout << " " << n_out(alg); - cout << endl; - } -#endif -} - -void FmCore::render(int32_t *output, FmOpParams *params, int algorithm, int32_t *fb_buf, int32_t feedback_shift) { - const int kLevelThresh = 1120; - const FmAlgorithm alg = algorithms[algorithm]; - bool has_contents[3] = { true, false, false }; - for (int op = 0; op < 6; op++) { - int flags = alg.ops[op]; - bool add = (flags & OUT_BUS_ADD) != 0; - FmOpParams ¶m = params[op]; - int inbus = (flags >> 4) & 3; - int outbus = flags & 3; - int32_t *outptr = (outbus == 0) ? output : buf_[outbus - 1].get(); - int32_t gain1 = param.gain_out; - int32_t gain2 = Exp2::lookup(param.level_in - (14 * (1 << 24))); - param.gain_out = gain2; - - if (gain1 >= kLevelThresh || gain2 >= kLevelThresh) { - if (!has_contents[outbus]) { - add = false; - } - if (inbus == 0 || !has_contents[inbus]) { - // todo: more than one op in a feedback loop - if ((flags & 0xc0) == 0xc0 && feedback_shift < 16) { - // cout << op << " fb " << inbus << outbus << add << endl; - FmOpKernel::compute_fb(outptr, param.phase, param.freq, - gain1, gain2, - fb_buf, feedback_shift, add); - } else { - // cout << op << " pure " << inbus << outbus << add << endl; - FmOpKernel::compute_pure(outptr, param.phase, param.freq, - gain1, gain2, add); - } - } else { - // cout << op << " normal " << inbus << outbus << " " << param.freq << add << endl; - FmOpKernel::compute(outptr, buf_[inbus - 1].get(), - param.phase, param.freq, gain1, gain2, add); - } - has_contents[outbus] = true; - } else if (!add) { - has_contents[outbus] = false; - } - param.phase += param.freq << LG_N; - } -} diff --git a/src/msfa/fm_core.h b/src/msfa/fm_core.h deleted file mode 100644 index b1ec263..0000000 --- a/src/msfa/fm_core.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __FM_CORE_H -#define __FM_CORE_H - -#include "aligned_buf.h" -#include "fm_op_kernel.h" -#include "synth.h" -#include "controllers.h" - - -class FmOperatorInfo { -public: - int in; - int out; -}; - -enum FmOperatorFlags { - OUT_BUS_ONE = 1 << 0, - OUT_BUS_TWO = 1 << 1, - OUT_BUS_ADD = 1 << 2, - IN_BUS_ONE = 1 << 4, - IN_BUS_TWO = 1 << 5, - FB_IN = 1 << 6, - FB_OUT = 1 << 7 -}; - -class FmAlgorithm { -public: - int ops[6]; -}; - -class FmCore { -public: - virtual ~FmCore() {}; - static void dump(); - virtual void render(int32_t *output, FmOpParams *params, int algorithm, int32_t *fb_buf, int32_t feedback_gain); -protected: - AlignedBufbuf_[2]; - const static FmAlgorithm algorithms[32]; -}; - -#endif // __FM_CORE_H diff --git a/src/msfa/fm_op_kernel.cc b/src/msfa/fm_op_kernel.cc deleted file mode 100644 index a14ff6a..0000000 --- a/src/msfa/fm_op_kernel.cc +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include - -#ifdef HAVE_NEON -#include -#endif - -#include "synth.h" -#include "sin.h" -#include "fm_op_kernel.h" - -#ifdef HAVE_NEONx -static bool hasNeon() { - return true; - return (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0; -} - -extern "C" -void neon_fm_kernel(const int *in, const int *busin, int *out, int count, - int32_t phase0, int32_t freq, int32_t gain1, int32_t dgain); - -const int32_t __attribute__ ((aligned(16))) zeros[N] = {0}; - -#else -static bool hasNeon() { - return false; -} -#endif - -void FmOpKernel::compute(int32_t *output, const int32_t *input, - int32_t phase0, int32_t freq, - int32_t gain1, int32_t gain2, bool add) { - int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; - int32_t gain = gain1; - int32_t phase = phase0; - if (hasNeon()) { -#ifdef HAVE_NEON - neon_fm_kernel(input, add ? output : zeros, output, N, - phase0, freq, gain, dgain); -#endif - } else { - if (add) { - for (int i = 0; i < N; i++) { - gain += dgain; - int32_t y = Sin::lookup(phase + input[i]); - int32_t y1 = ((int64_t)y * (int64_t)gain) >> 24; - output[i] += y1; - phase += freq; - } - } else { - for (int i = 0; i < N; i++) { - gain += dgain; - int32_t y = Sin::lookup(phase + input[i]); - int32_t y1 = ((int64_t)y * (int64_t)gain) >> 24; - output[i] = y1; - phase += freq; - } - } - } -} - -void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq, - int32_t gain1, int32_t gain2, bool add) { - int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; - int32_t gain = gain1; - int32_t phase = phase0; - if (hasNeon()) { -#ifdef HAVE_NEON - neon_fm_kernel(zeros, add ? output : zeros, output, N, - phase0, freq, gain, dgain); -#endif - } else { - if (add) { - for (int i = 0; i < N; i++) { - gain += dgain; - int32_t y = Sin::lookup(phase); - int32_t y1 = ((int64_t)y * (int64_t)gain) >> 24; - output[i] += y1; - phase += freq; - } - } else { - for (int i = 0; i < N; i++) { - gain += dgain; - int32_t y = Sin::lookup(phase); - int32_t y1 = ((int64_t)y * (int64_t)gain) >> 24; - output[i] = y1; - phase += freq; - } - } - } -} - -#define noDOUBLE_ACCURACY -#define HIGH_ACCURACY - -void FmOpKernel::compute_fb(int32_t *output, int32_t phase0, int32_t freq, - int32_t gain1, int32_t gain2, - int32_t *fb_buf, int fb_shift, bool add) { - int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; - int32_t gain = gain1; - int32_t phase = phase0; - int32_t y0 = fb_buf[0]; - int32_t y = fb_buf[1]; - if (add) { - for (int i = 0; i < N; i++) { - gain += dgain; - int32_t scaled_fb = (y0 + y) >> (fb_shift + 1); - y0 = y; - y = Sin::lookup(phase + scaled_fb); - y = ((int64_t)y * (int64_t)gain) >> 24; - output[i] += y; - phase += freq; - } - } else { - for (int i = 0; i < N; i++) { - gain += dgain; - int32_t scaled_fb = (y0 + y) >> (fb_shift + 1); - y0 = y; - y = Sin::lookup(phase + scaled_fb); - y = ((int64_t)y * (int64_t)gain) >> 24; - output[i] = y; - phase += freq; - } - } - fb_buf[0] = y0; - fb_buf[1] = y; -} - -//////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////// - -// Experimental sine wave generators below -#if 0 -// Results: accuracy 64.3 mean, 170 worst case -// high accuracy: 5.0 mean, 49 worst case -void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq, - int32_t gain1, int32_t gain2, bool add) { - int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; - int32_t gain = gain1; - int32_t phase = phase0; -#ifdef HIGH_ACCURACY - int32_t u = Sin::compute10(phase << 6); - u = ((int64_t)u * gain) >> 30; - int32_t v = Sin::compute10((phase << 6) + (1 << 28)); // quarter cycle - v = ((int64_t)v * gain) >> 30; - int32_t s = Sin::compute10(freq << 6); - int32_t c = Sin::compute10((freq << 6) + (1 << 28)); -#else - int32_t u = Sin::compute(phase); - u = ((int64_t)u * gain) >> 24; - int32_t v = Sin::compute(phase + (1 << 22)); // quarter cycle - v = ((int64_t)v * gain) >> 24; - int32_t s = Sin::compute(freq) << 6; - int32_t c = Sin::compute(freq + (1 << 22)) << 6; -#endif - for (int i = 0; i < N; i++) { - output[i] = u; - int32_t t = ((int64_t)v * (int64_t)c - (int64_t)u * (int64_t)s) >> 30; - u = ((int64_t)u * (int64_t)c + (int64_t)v * (int64_t)s) >> 30; - v = t; - } -} -#endif - -#if 0 -// Results: accuracy 392.3 mean, 15190 worst case (near freq = 0.5) -// for freq < 0.25, 275.2 mean, 716 worst -// high accuracy: 57.4 mean, 7559 worst -// freq < 0.25: 17.9 mean, 78 worst -void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq, - int32_t gain1, int32_t gain2, bool add) { - int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; - int32_t gain = gain1; - int32_t phase = phase0; -#ifdef HIGH_ACCURACY - int32_t u = floor(gain * sin(phase * (M_PI / (1 << 23))) + 0.5); - int32_t v = floor(gain * cos((phase - freq * 0.5) * (M_PI / (1 << 23))) + 0.5); - int32_t a = floor((1 << 25) * sin(freq * (M_PI / (1 << 24))) + 0.5); -#else - int32_t u = Sin::compute(phase); - u = ((int64_t)u * gain) >> 24; - int32_t v = Sin::compute(phase + (1 << 22) - (freq >> 1)); - v = ((int64_t)v * gain) >> 24; - int32_t a = Sin::compute(freq >> 1) << 1; -#endif - for (int i = 0; i < N; i++) { - output[i] = u; - v -= ((int64_t)a * (int64_t)u) >> 24; - u += ((int64_t)a * (int64_t)v) >> 24; - } -} -#endif - -#if 0 -// Results: accuracy 370.0 mean, 15480 worst case (near freq = 0.5) -// with double accuracy initialization: mean 1.55, worst 58 (near freq = 0) -// with high accuracy: mean 4.2, worst 292 (near freq = 0.5) -void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq, - int32_t gain1, int32_t gain2, bool add) { - int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; - int32_t gain = gain1; - int32_t phase = phase0; -#ifdef DOUBLE_ACCURACY - int32_t u = floor((1 << 30) * sin(phase * (M_PI / (1 << 23))) + 0.5); - double a_d = sin(freq * (M_PI / (1 << 24))); - int32_t v = floor((1LL << 31) * a_d * cos((phase - freq * 0.5) * - (M_PI / (1 << 23))) + 0.5); - int32_t aa = floor((1LL << 31) * a_d * a_d + 0.5); -#else -#ifdef HIGH_ACCURACY - int32_t u = Sin::compute10(phase << 6); - int32_t v = Sin::compute10((phase << 6) + (1 << 28) - (freq << 5)); - int32_t a = Sin::compute10(freq << 5); - v = ((int64_t)v * (int64_t)a) >> 29; - int32_t aa = ((int64_t)a * (int64_t)a) >> 29; -#else - int32_t u = Sin::compute(phase) << 6; - int32_t v = Sin::compute(phase + (1 << 22) - (freq >> 1)); - int32_t a = Sin::compute(freq >> 1); - v = ((int64_t)v * (int64_t)a) >> 17; - int32_t aa = ((int64_t)a * (int64_t)a) >> 17; -#endif -#endif - - if (aa < 0) aa = (1 << 31) - 1; - for (int i = 0; i < N; i++) { - gain += dgain; - output[i] = ((int64_t)u * (int64_t)gain) >> 30; - v -= ((int64_t)aa * (int64_t)u) >> 29; - u += v; - } -} -#endif - -#if 0 -// Results:: accuracy 112.3 mean, 4262 worst (near freq = 0.5) -// high accuracy 2.9 mean, 143 worst -void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq, - int32_t gain1, int32_t gain2, bool add) { - int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; - int32_t gain = gain1; - int32_t phase = phase0; -#ifdef HIGH_ACCURACY - int32_t u = Sin::compute10(phase << 6); - int32_t lastu = Sin::compute10((phase - freq) << 6); - int32_t a = Sin::compute10((freq << 6) + (1 << 28)) << 1; -#else - int32_t u = Sin::compute(phase) << 6; - int32_t lastu = Sin::compute(phase - freq) << 6; - int32_t a = Sin::compute(freq + (1 << 22)) << 7; -#endif - if (a < 0 && freq < 256) a = (1 << 31) - 1; - if (a > 0 && freq > 0x7fff00) a = -(1 << 31); - for (int i = 0; i < N; i++) { - gain += dgain; - output[i] = ((int64_t)u * (int64_t)gain) >> 30; - //output[i] = u; - int32_t newu = (((int64_t)u * (int64_t)a) >> 30) - lastu; - lastu = u; - u = newu; - } -} -#endif - diff --git a/src/msfa/fm_op_kernel.h b/src/msfa/fm_op_kernel.h deleted file mode 100644 index c9739e5..0000000 --- a/src/msfa/fm_op_kernel.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __FM_OP_KERNEL_H -#define __FM_OP_KERNEL_H - -struct FmOpParams { - int32_t level_in; // value to be computed (from level to gain[0]) - int32_t gain_out; // computed value (gain[1] to gain[0]) - int32_t freq; - int32_t phase; -}; - -class FmOpKernel { - public: - // gain1 and gain2 represent linear step: gain for sample i is - // gain1 + (1 + i) / 64 * (gain2 - gain1) - - // This is the basic FM operator. No feedback. - static void compute(int32_t *output, const int32_t *input, - int32_t phase0, int32_t freq, - int32_t gain1, int32_t gain2, bool add); - - // This is a sine generator, no feedback. - static void compute_pure(int32_t *output, int32_t phase0, int32_t freq, - int32_t gain1, int32_t gain2, bool add); - - // One op with feedback, no add. - static void compute_fb(int32_t *output, int32_t phase0, int32_t freq, - int32_t gain1, int32_t gain2, - int32_t *fb_buf, int fb_gain, bool add); -}; - -#endif diff --git a/src/msfa/freqlut.cc b/src/msfa/freqlut.cc deleted file mode 100644 index 931ef67..0000000 --- a/src/msfa/freqlut.cc +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// Resolve frequency signal (1.0 in Q24 format = 1 octave) to phase delta. - -// The LUT is just a global, and we'll need the init function to be called before -// use. - -#include -#include - -#include "freqlut.h" - -#define LG_N_SAMPLES 10 -#define N_SAMPLES (1 << LG_N_SAMPLES) -#define SAMPLE_SHIFT (24 - LG_N_SAMPLES) - -#define MAX_LOGFREQ_INT 20 - -int32_t lut[N_SAMPLES + 1]; - -void Freqlut::init(double sample_rate) { - double y = (1LL << (24 + MAX_LOGFREQ_INT)) / sample_rate; - double inc = pow(2, 1.0 / N_SAMPLES); - for (int i = 0; i < N_SAMPLES + 1; i++) { - lut[i] = (int32_t)floor(y + 0.5); - y *= inc; - } -} - -// Note: if logfreq is more than 20.0, the results will be inaccurate. However, -// that will be many times the Nyquist rate. -int32_t Freqlut::lookup(int32_t logfreq) { - int ix = (logfreq & 0xffffff) >> SAMPLE_SHIFT; - - int32_t y0 = lut[ix]; - int32_t y1 = lut[ix + 1]; - int lowbits = logfreq & ((1 << SAMPLE_SHIFT) - 1); - int32_t y = y0 + ((((int64_t)(y1 - y0) * (int64_t)lowbits)) >> SAMPLE_SHIFT); - int hibits = logfreq >> 24; - return y >> (MAX_LOGFREQ_INT - hibits); -} diff --git a/src/msfa/freqlut.h b/src/msfa/freqlut.h deleted file mode 100644 index 5cba4af..0000000 --- a/src/msfa/freqlut.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -class Freqlut { - public: - static void init(double sample_rate); - static int32_t lookup(int32_t logfreq); -}; diff --git a/src/msfa/lfo.cc b/src/msfa/lfo.cc deleted file mode 100644 index b9b71de..0000000 --- a/src/msfa/lfo.cc +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2013 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// Low frequency oscillator, compatible with DX7 - -#include "synth.h" - -#include "sin.h" -#include "lfo.h" - -uint32_t Lfo::unit_; - -void Lfo::init(double sample_rate) { - // constant is 1 << 32 / 15.5s / 11 - Lfo::unit_ = (int32_t)(N * 25190424 / sample_rate + 0.5); -} - -void Lfo::reset(const uint8_t params[6]) { - int rate = params[0]; // 0..99 - int sr = rate == 0 ? 1 : (165 * rate) >> 6; - sr *= sr < 160 ? 11 : (11 + ((sr - 160) >> 4)); - delta_ = unit_ * sr; - int a = 99 - params[1]; // LFO delay - if (a == 99) { - delayinc_ = ~0u; - delayinc2_ = ~0u; - } else { - a = (16 + (a & 15)) << (1 + (a >> 4)); - delayinc_ = unit_ * a; - a &= 0xff80; - a = max(0x80, a); - delayinc2_ = unit_ * a; - } - waveform_ = params[5]; - sync_ = params[4] != 0; -} - -int32_t Lfo::getsample() { - phase_ += delta_; - int32_t x; - switch (waveform_) { - case 0: // triangle - x = phase_ >> 7; - x ^= -(phase_ >> 31); - x &= (1 << 24) - 1; - return x; - case 1: // sawtooth down - return (~phase_ ^ (1U << 31)) >> 8; - case 2: // sawtooth up - return (phase_ ^ (1U << 31)) >> 8; - case 3: // square - return ((~phase_) >> 7) & (1 << 24); - case 4: // sine - return (1 << 23) + (Sin::lookup(phase_ >> 8) >> 1); - case 5: // s&h - if (phase_ < delta_) { - randstate_ = (randstate_ * 179 + 17) & 0xff; - } - x = randstate_ ^ 0x80; - return (x + 1) << 16; - } - return 1 << 23; -} - -int32_t Lfo::getdelay() { - uint32_t delta = delaystate_ < (1U << 31) ? delayinc_ : delayinc2_; - uint64_t d = ((uint64_t)delaystate_) + delta; - if (d > ~0u) { - return 1 << 24; - } - delaystate_ = d; - if (d < (1U << 31)) { - return 0; - } else { - return (d >> 7) & ((1 << 24) - 1); - } -} - -void Lfo::keydown() { - if (sync_) { - phase_ = (1U << 31) - 1; - } - delaystate_ = 0; -} diff --git a/src/msfa/lfo.h b/src/msfa/lfo.h deleted file mode 100644 index c7c0a9c..0000000 --- a/src/msfa/lfo.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2013 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// Low frequency oscillator, compatible with DX7 - -class Lfo { - public: - static void init(double sample_rate); - void reset(const uint8_t params[6]); - - // result is 0..1 in Q24 - int32_t getsample(); - - // result is 0..1 in Q24 - int32_t getdelay(); - - void keydown(); - private: - static uint32_t unit_; - - uint32_t phase_; // Q32 - uint32_t delta_; - uint8_t waveform_; - uint8_t randstate_; - bool sync_; - - uint32_t delaystate_; - uint32_t delayinc_; - uint32_t delayinc2_; -}; diff --git a/src/msfa/module.h b/src/msfa/module.h deleted file mode 100644 index e165531..0000000 --- a/src/msfa/module.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SYNTH_MODULE_H -#define SYNTH_MODULE_H - -#include - -class Module { - public: - static const int lg_n = 6; - static const int n = 1 << lg_n; - virtual void process(const int32_t **inbufs, const int32_t *control_in, - const int32_t *control_last, int32_t **outbufs) = 0; -}; - -#endif // SYNTH_MODULE_H - diff --git a/src/msfa/pitchenv.cc b/src/msfa/pitchenv.cc deleted file mode 100644 index a85b8d4..0000000 --- a/src/msfa/pitchenv.cc +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "synth.h" -#include "pitchenv.h" - -int PitchEnv::unit_; - -void PitchEnv::init(double sample_rate) { - unit_ = N * (1 << 24) / (21.3 * sample_rate) + 0.5; -} - -const uint8_t pitchenv_rate[] = { - 1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, - 12, 13, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 30, 31, 33, 34, 36, 37, 38, 39, 41, 42, 44, 46, 47, - 49, 51, 53, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 79, 82, - 85, 88, 91, 94, 98, 102, 106, 110, 115, 120, 125, 130, 135, 141, 147, - 153, 159, 165, 171, 178, 185, 193, 202, 211, 232, 243, 254, 255 -}; - -const int8_t pitchenv_tab[] = { - -128, -116, -104, -95, -85, -76, -68, -61, -56, -52, -49, -46, -43, - -41, -39, -37, -35, -33, -32, -31, -30, -29, -28, -27, -26, -25, -24, - -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, -11, -10, - -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 31, 32, 33, 34, 35, 38, 40, 43, 46, 49, 53, 58, 65, 73, - 82, 92, 103, 115, 127 -}; - -void PitchEnv::set(const int r[4], const int l[4]) { - for (int i = 0; i < 4; i++) { - rates_[i] = r[i]; - levels_[i] = l[i]; - } - level_ = pitchenv_tab[l[3]] << 19; - down_ = true; - advance(0); -} - -int32_t PitchEnv::getsample() { - if (ix_ < 3 || ((ix_ < 4) && !down_)) { - if (rising_) { - level_ += inc_; - if (level_ >= targetlevel_) { - level_ = targetlevel_; - advance(ix_ + 1); - } - } else { // !rising - level_ -= inc_; - if (level_ <= targetlevel_) { - level_ = targetlevel_; - advance(ix_ + 1); - } - } - } - return level_; -} - -void PitchEnv::keydown(bool d) { - if (down_ != d) { - down_ = d; - advance(d ? 0 : 3); - } -} - -void PitchEnv::advance(int newix) { - ix_ = newix; - if (ix_ < 4) { - int newlevel = levels_[ix_]; - targetlevel_ = pitchenv_tab[newlevel] << 19; - rising_ = (targetlevel_ > level_); - inc_ = pitchenv_rate[rates_[ix_]] * unit_; - } -} - -void PitchEnv::getPosition(char *step) { - *step = ix_; -} - - diff --git a/src/msfa/pitchenv.h b/src/msfa/pitchenv.h deleted file mode 100644 index e106341..0000000 --- a/src/msfa/pitchenv.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2013 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __PITCHENV_H -#define __PITCHENV_H - -// Computation of the DX7 pitch envelope - -class PitchEnv { - public: - static void init(double sample_rate); - - // The rates and levels arrays are calibrated to match the Dx7 parameters - // (ie, value 0..99). - void set(const int rates[4], const int levels[4]); - - // Result is in Q24/octave - int32_t getsample(); - void keydown(bool down); - void getPosition(char *step); - private: - static int unit_; - int rates_[4]; - int levels_[4]; - int32_t level_; - int targetlevel_; - bool rising_; - int ix_; - int inc_; - - bool down_; - - void advance(int newix); -}; - -extern const uint8_t pitchenv_rate[]; -extern const int8_t pitchenv_tab[]; - - #endif // __PITCHENV_H - diff --git a/src/msfa/sin.cc b/src/msfa/sin.cc deleted file mode 100644 index 8a8471f..0000000 --- a/src/msfa/sin.cc +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define _USE_MATH_DEFINES -#include - -#include "synth.h" -#include "sin.h" - -#define R (1 << 29) -#define M_PI 3.1415926 - -#ifdef SIN_DELTA -int32_t sintab[SIN_N_SAMPLES << 1]; -#else -int32_t sintab[SIN_N_SAMPLES + 1]; -#endif - -void Sin::init() { - double dphase = 2 * M_PI / SIN_N_SAMPLES; - int32_t c = (int32_t)floor(cos(dphase) * (1 << 30) + 0.5); - int32_t s = (int32_t)floor(sin(dphase) * (1 << 30) + 0.5); - int32_t u = 1 << 30; - int32_t v = 0; - for (int i = 0; i < SIN_N_SAMPLES / 2; i++) { -#ifdef SIN_DELTA - sintab[(i << 1) + 1] = (v + 32) >> 6; - sintab[((i + SIN_N_SAMPLES / 2) << 1) + 1] = -((v + 32) >> 6); -#else - sintab[i] = (v + 32) >> 6; - sintab[i + SIN_N_SAMPLES / 2] = -((v + 32) >> 6); -#endif - int32_t t = ((int64_t)u * (int64_t)s + (int64_t)v * (int64_t)c + R) >> 30; - u = ((int64_t)u * (int64_t)c - (int64_t)v * (int64_t)s + R) >> 30; - v = t; - } -#ifdef SIN_DELTA - for (int i = 0; i < SIN_N_SAMPLES - 1; i++) { - sintab[i << 1] = sintab[(i << 1) + 3] - sintab[(i << 1) + 1]; - } - sintab[(SIN_N_SAMPLES << 1) - 2] = -sintab[(SIN_N_SAMPLES << 1) - 1]; -#else - sintab[SIN_N_SAMPLES] = 0; -#endif -} - -#ifndef SIN_INLINE -int32_t Sin::lookup(int32_t phase) { - const int SHIFT = 24 - SIN_LG_N_SAMPLES; - int lowbits = phase & ((1 << SHIFT) - 1); -#ifdef SIN_DELTA - int phase_int = (phase >> (SHIFT - 1)) & ((SIN_N_SAMPLES - 1) << 1); - int dy = sintab[phase_int]; - int y0 = sintab[phase_int + 1]; - - return y0 + (((int64_t)dy * (int64_t)lowbits) >> SHIFT); -#else - int phase_int = (phase >> SHIFT) & (SIN_N_SAMPLES - 1); - int y0 = sintab[phase_int]; - int y1 = sintab[phase_int + 1]; - - return y0 + (((int64_t)(y1 - y0) * (int64_t)lowbits) >> SHIFT); -#endif -} -#endif - - -#if 0 -// The following is an implementation designed not to use any lookup tables, -// based on the following implementation by Basile Graf: -// http://www.rossbencina.com/static/code/sinusoids/even_polynomial_sin_approximation.txt - -#define C0 (1 << 24) -#define C1 (331121857 >> 2) -#define C2 (1084885537 >> 4) -#define C3 (1310449902 >> 6) - -int32_t Sin::compute(int32_t phase) { - int32_t x = (phase & ((1 << 23) - 1)) - (1 << 22); - int32_t x2 = ((int64_t)x * (int64_t)x) >> 22; - int32_t x4 = ((int64_t)x2 * (int64_t)x2) >> 24; - int32_t x6 = ((int64_t)x2 * (int64_t)x4) >> 24; - int32_t y = C0 - - (((int64_t)C1 * (int64_t)x2) >> 24) + - (((int64_t)C2 * (int64_t)x4) >> 24) - - (((int64_t)C3 * (int64_t)x6) >> 24); - y ^= -((phase >> 23) & 1); - return y; -} -#endif - -#if 1 -// coefficients are Chebyshev polynomial, computed by compute_cos_poly.py -#define C8_0 16777216 -#define C8_2 -331168742 -#define C8_4 1089453524 -#define C8_6 -1430910663 -#define C8_8 950108533 - -int32_t Sin::compute(int32_t phase) { - int32_t x = (phase & ((1 << 23) - 1)) - (1 << 22); - int32_t x2 = ((int64_t)x * (int64_t)x) >> 16; - int32_t y = (((((((((((((int64_t)C8_8 - * (int64_t)x2) >> 32) + C8_6) - * (int64_t)x2) >> 32) + C8_4) - * (int64_t)x2) >> 32) + C8_2) - * (int64_t)x2) >> 32) + C8_0); - y ^= -((phase >> 23) & 1); - return y; -} -#endif - -#define C10_0 (1 << 30) -#define C10_2 -1324675874 // scaled * 4 -#define C10_4 1089501821 -#define C10_6 -1433689867 -#define C10_8 1009356886 -#define C10_10 -421101352 -int32_t Sin::compute10(int32_t phase) { - int32_t x = (phase & ((1 << 29) - 1)) - (1 << 28); - int32_t x2 = ((int64_t)x * (int64_t)x) >> 26; - int32_t y = ((((((((((((((((int64_t)C10_10 - * (int64_t)x2) >> 34) + C10_8) - * (int64_t)x2) >> 34) + C10_6) - * (int64_t)x2) >> 34) + C10_4) - * (int64_t)x2) >> 32) + C10_2) - * (int64_t)x2) >> 30) + C10_0); - y ^= -((phase >> 29) & 1); - return y; -} diff --git a/src/msfa/sin.h b/src/msfa/sin.h deleted file mode 100644 index 6605e99..0000000 --- a/src/msfa/sin.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -class Sin { - public: - Sin(); - - static void init(); - static int32_t lookup(int32_t phase); - static int32_t compute(int32_t phase); - - // A more accurate sine, both input and output Q30 - static int32_t compute10(int32_t phase); -}; - -#define SIN_LG_N_SAMPLES 10 -#define SIN_N_SAMPLES (1 << SIN_LG_N_SAMPLES) - -#define SIN_INLINE - -// Use twice as much RAM for the LUT but avoid a little computation -#define SIN_DELTA - -#ifdef SIN_DELTA -extern int32_t sintab[SIN_N_SAMPLES << 1]; -#else -extern int32_t sintab[SIN_N_SAMPLES + 1]; -#endif - -#ifdef SIN_INLINE -inline -int32_t Sin::lookup(int32_t phase) { - const int SHIFT = 24 - SIN_LG_N_SAMPLES; - int lowbits = phase & ((1 << SHIFT) - 1); -#ifdef SIN_DELTA - int phase_int = (phase >> (SHIFT - 1)) & ((SIN_N_SAMPLES - 1) << 1); - int dy = sintab[phase_int]; - int y0 = sintab[phase_int + 1]; - - return y0 + (((int64_t)dy * (int64_t)lowbits) >> SHIFT); -#else - int phase_int = (phase >> SHIFT) & (SIN_N_SAMPLES - 1); - int y0 = sintab[phase_int]; - int y1 = sintab[phase_int + 1]; - - return y0 + (((int64_t)(y1 - y0) * (int64_t)lowbits) >> SHIFT); -#endif -} -#endif diff --git a/src/msfa/synth.h b/src/msfa/synth.h deleted file mode 100644 index c64005b..0000000 --- a/src/msfa/synth.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __SYNTH_H -#define __SYNTH_H - -// This IS not be present on MSVC. -// See http://stackoverflow.com/questions/126279/c99-stdint-h-header-and-ms-visual-studio -#include -#ifdef _MSC_VER -typedef __int32 int32_t; -typedef unsigned __int32 uint32_t; -typedef __int16 SInt16; -#endif - -const static int LG_N = 6; -const static int N = (1 << LG_N); - -#if defined(__APPLE__) -#include -#define SynthMemoryBarrier() OSMemoryBarrier() -#elif defined(__GNUC__) -#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) -#define SynthMemoryBarrier() __sync_synchronize() -#endif -#endif - - -// #undef SynthMemoryBarrier() - -#ifndef SynthMemoryBarrier -// need to understand why this must be defined -// #warning Memory barrier is not enabled -#define SynthMemoryBarrier() -#endif - -template -inline static T min(const T& a, const T& b) { - return a < b ? a : b; -} - -template -inline static T max(const T& a, const T& b) { - return a > b ? a : b; -} - -void dexed_trace(const char *source, const char *fmt, ...); - -#define QER(n,b) ( ((float)n)/(1< -#include -#include -#include -#include -#include -#include - - -struct StandardTuning : public TuningState { - StandardTuning() { - const int base = 50857777; // (1 << 24) * (log(440) / log(2) - 69/12) - const int step = (1 << 24) / 12; - for( int mn = 0; mn < 128; ++mn ) - { - auto res = base + step * mn; - current_logfreq_table_[mn] = res; - } - } - - virtual int32_t midinote_to_logfreq(int midinote) override { - return current_logfreq_table_[midinote]; - } - - int current_logfreq_table_[128]; -}; - - -struct SCLAndKBMTuningState : public TuningState { - virtual bool is_standard_tuning() override { - return false; - } - - virtual int32_t midinote_to_logfreq(int midinote) override { - const int base = 50857777; - const int step = ( 1 << 24 ); - return tuning.logScaledFrequencyForMidiNote( midinote ) * step + base; - } - - virtual int scale_length() { return tuning.scale.count; } - virtual std::string display_tuning_str() { return "SCL KBM Tuning"; } - - virtual Tunings::Tuning &getTuning() override { return tuning; } - - Tunings::Tuning tuning; - -}; - -std::shared_ptr createStandardTuning() -{ - return std::make_shared(); -} - -std::shared_ptr createTuningFromSCLData( const std::string &scl ) -{ - auto s = Tunings::parseSCLData(scl); - auto res = std::make_shared(); - res->tuning = Tunings::Tuning( s ); - return res; -} - -std::shared_ptr createTuningFromKBMData( const std::string &kbm ) -{ - auto k = Tunings::parseKBMData(kbm); - auto res = std::make_shared(); - res->tuning = Tunings::Tuning( k ); - return res; -} - -std::shared_ptr createTuningFromSCLAndKBMData( const std::string &sclData, const std::string &kbmData ) -{ - auto s = Tunings::parseSCLData(sclData); - auto k = Tunings::parseKBMData(kbmData); - auto res = std::make_shared(); - res->tuning = Tunings::Tuning( s, k ); - return res; -} diff --git a/src/msfa/tuning.h b/src/msfa/tuning.h deleted file mode 100644 index cf7f287..0000000 --- a/src/msfa/tuning.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef __SYNTH_TUNING_H -#define __SYNTH_TUNING_H - -#include "synth.h" -#include -#include -#include "Tunings.h" - -class TuningState { -public: - virtual ~TuningState() { } - - virtual int32_t midinote_to_logfreq(int midinote) = 0; - virtual bool is_standard_tuning() { return true; } - virtual int scale_length() { return 12; } - virtual std::string display_tuning_str() { return "Standard Tuning"; } - - virtual Tunings::Tuning &getTuning() { - static Tunings::Tuning t; - return t; - } -}; - -std::shared_ptr createStandardTuning(); - -std::shared_ptr createTuningFromSCLData( const std::string &sclData ); -std::shared_ptr createTuningFromKBMData( const std::string &kbmData ); -std::shared_ptr createTuningFromSCLAndKBMData( const std::string &sclData, const std::string &kbmData ); - -#endif