diff --git a/Builds/MacOSX/Dexed.xcodeproj/project.pbxproj b/Builds/MacOSX/Dexed.xcodeproj/project.pbxproj index 9a0c6d6..7bc398e 100644 --- a/Builds/MacOSX/Dexed.xcodeproj/project.pbxproj +++ b/Builds/MacOSX/Dexed.xcodeproj/project.pbxproj @@ -892,8 +892,8 @@ 0652CE27AE4971C99654E3BF = {isa = PBXGroup; children = ( 8BADEB7BF1A65E83A7A1736D, DC75DFCDFCDB425927B11EC0, - C222D35AC4FC5C2A3BB0F8B6, 8BEBEDCAD409EE3A5D383B6D, + C222D35AC4FC5C2A3BB0F8B6, 61F792AFE04C15F413A4F766, 7A58027CF8C6967B02370E01, ); name = dsp; sourceTree = ""; }; 427DD4218ED26D69B0149A90 = {isa = PBXGroup; children = ( diff --git a/Builds/MacOSX/Dexed.xcodeproj/project.xcworkspace/xcuserdata/asb2m10.xcuserdatad/UserInterfaceState.xcuserstate b/Builds/MacOSX/Dexed.xcodeproj/project.xcworkspace/xcuserdata/asb2m10.xcuserdatad/UserInterfaceState.xcuserstate index 48980d8..7ee7cd1 100644 Binary files a/Builds/MacOSX/Dexed.xcodeproj/project.xcworkspace/xcuserdata/asb2m10.xcuserdatad/UserInterfaceState.xcuserstate and b/Builds/MacOSX/Dexed.xcodeproj/project.xcworkspace/xcuserdata/asb2m10.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Dexed.jucer b/Dexed.jucer index 4e6eb14..c44d3fa 100644 --- a/Dexed.jucer +++ b/Dexed.jucer @@ -19,8 +19,8 @@ - + diff --git a/README.md b/README.md index 2d2b7b8..74104a3 100644 --- a/README.md +++ b/README.md @@ -10,12 +10,12 @@ with 'float' value parameters, different waveform à la TX81z would be great but goes beyond the DX7 should and will be a fork of this project. This is to keep the compatibility with the original machine. -Dexed is licensed on the GPL v2. The msfa component (acronym for music synthesizer for android, see msfa +Dexed is licensed on the GPL v3. The msfa component (acronym for music synthesizer for android, see msfa in the source folder) stays on the Apache 2.0 license to able to collaborate between projects. Features -------- -* Multi platform (OS X, Windows or Linux) and multi format (VST, AU and others that I don't use); by using JUCE +* Multi platform (OS X, Windows or Linux) and multi format (VST, *soon* AU and others that I don't use); by using JUCE * The sound engine [music-synthesizer-for-android](https://code.google.com/p/music-synthesizer-for-android) is closely modeled on the original DX7 characteristics * 144 DAW automatable DX7 parameters available from one single panel * Fully supports DX7 input and output Sysex messages; including controller change. This means that you can use this with a native DX7/TX7 as a patch editor and sysex manager @@ -29,18 +29,20 @@ in normal operation it shouldn't crash and the VST state saving works. If you do new version here but you see it in the change log, it's because this version is in development (current sprint). Only officials (tested) builds are listed here. +* Version 0.7.0 OMG ! * Version 0.6.1 [vst win32/x64](http://le-son666.com/software/dexed/dexed-0.6.1-win.zip) - [vst os x](http://le-son666.com/software/dexed/dexed-0.6.1-osx.vst.zip) Changelog --------- #### Version 0.7.0 (current sprint) * Preliminary Algo 4 & 6 feedback support -* DX Engine 'Dirty DX' emulation, including based on OPL chips -* DX Engine LFO amplitude. This still needs some tunings -* Fixed stucked notes when programs where changed +* DX Engine 'Dirty DX' emulation, including one based on OPL chips +* DX Engine LFO amplitude. This still needs some tunings :( +* Monophonic mode * Added the 'INIT' button to re-initialize a program -* Fixed engine envelop wrong timing if it was not 44100Khz -* Filter only .syx files when using the Dexed_cart.zip file +* Fixed stucked notes when programs where changed +* Fixed engine envelopes wrong timing if it was not 44100Khz +* Fixed only .syx are shown when we are using the Dexed_cart.zip cartridges collection #### Version 0.6.1 * Mouse over + LFO type fix + pitch eg values @@ -61,22 +63,17 @@ sysex content to where you have installed Dexed (VST plugins dir). Then rename t file is changed. Directories in the zip file will be transformed into submenu when you hit the [CART] button. Watch out; Windows hides the .zip extension by default ! -Engine resolutions ------------------- -Dexed can be configured to try to use the original math limitation of a DX synthesizer. And when I say -math limitation, I'm not only talking about the DAC, it is also about the sin LUT lookup table, multiply -resolution and original DX sampling rate. This is a work in progress and this might take time to be able -to perfect. - -If you look at the original DX7 and implementation a DX engine with 10-bit sin lookup and 12 mul possibility, -you get something "not quite there". Yamaha did a lot of hacks to be able to squeeze this into something -musical and expressive. It is those 'hacks' that we need to recreate to be able to find that original -DX sound. +Engine Type +----------- +Dexed can be configured to try to use the original math limitation of a DX synthesizer. This does not +only apply to the DAC, it also involves the bit resolution of the sine waves and the way that the +amplitude is applied to each operator. Since all of this is experimental, multiple engines will be +available to be able to compare them easily. -Dexed comes with 3 engine resolutions : +Dexed comes with 3 engine types : * Modern : this is the original 24-bit music-synthesizer-for-android implementation. -* Mark I : this is a pale implementation of the limitation of a Yamaha DX7 Mark I with the 12-bit (with the 4-bit attenuator hack) DAC. -* OPL Series : this is a experimental implementation of Yamaha 4-ops that used the YM2151 chip. These chips were supposed to be even more limited to the DX7 but gave a very interesting distinctive sound. +* Mark I : It is the music-synthesizer-for-android implementation reduced to 8-bit. It is used to be able to see the difference between the OPL series that also uses 8-bit but with sums of logs to avoid multiplications. It will be upgraded to 10-bit/12-bit later. +* OPL Series : this is an experimental implementation of the [reversed engineered OPL family chips](http://sourceforge.net/projects/peepeeplayer). 8-bit. Keep in mind that the envelopes stills needs tuning. Using as a DX7 editor --------------------- @@ -104,7 +101,6 @@ you edit. ### Troubleshooting * If you play on your DX7 keyboard, the |DX7 In| light should be flashing. Use this to test the midi in communication. -* If you click/play on the Dexed virtual keyboard, it will send the corresponding midi out note to the DX7 port; if configured. Use this to test the midi out communication. * If the data sent is corrupted (wrong checksum, DX7 crash), it might be the midi interface implementation. Default Windows USB midi driver are known to send corrupt sysex data. If it is the case, use a third party device (like the midiman uno) that have his own USB driver. * If you are unable to open the interface (error message after the using the [PARM] dialog), it might be because the midi driver doesn't support multiple clients (common on Windows). Be sure that there are no other applications that are using the same midi interface. @@ -130,6 +126,7 @@ Credits & thanks ---------------- * DX Synth engine : Raph Levien and the [msfa](https://code.google.com/p/music-synthesizer-for-android) team * LP Filter : Filatov Vadim (2DaT); taken from the excellent [Obxd](https://obxd.wordpress.com) project +* PPPlay : Great [OPL3](http://sourceforge.net/projects/peepeeplayer) implementation, with documented code :D * DX7 program compilation : Jean-Marc Desprez (author of [SynprezFM](http://www.synprez.com/SynprezFM)) * DX7 programs : Dave Benson, Frank Carvalho, Tim Conrardy, Jack Deckard, Chris Dodunski, Tim Garrett, Hitaye, Stephan Ibsen, Christian Jezreel, Narfman, Godric Wilkie * markusthegeek direct implication for this project @@ -144,6 +141,7 @@ TODO - Dexed ------------ * Yamaha 4 operators (DX21/DX27/DX100) sysex import * Various code cleanup +* AU Version TODO - msfa ----------- diff --git a/Source/DXComponents.cpp b/Source/DXComponents.cpp index 3e7e9ed..3252b23 100644 --- a/Source/DXComponents.cpp +++ b/Source/DXComponents.cpp @@ -6,20 +6,20 @@ * Copyright (C) 2002 Juan Linietsky * Copyright (C) 2006 Mark-André Hopf * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. */ #include "DXComponents.h" @@ -425,7 +425,7 @@ void VuMeter::paint(Graphics &g) { g.setColour (Colours::black); g.fillRoundedRectangle (0.0f, 0.0f, (float) width, (float) height, 0); - const int numBlocks = roundToInt (totalBlocks * v); + const int numBlocks = roundToInt(totalBlocks * v); const float h = (height - 6.0f) / (float) totalBlocks; for (int i = 0; i < totalBlocks; ++i) { diff --git a/Source/DXComponents.h b/Source/DXComponents.h index e4a22da..7d6f29d 100644 --- a/Source/DXComponents.h +++ b/Source/DXComponents.h @@ -2,20 +2,20 @@ * * Copyright (c) 2014 Pascal Gauthier. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. */ #ifndef DXCOMPONENTS_H_INCLUDED diff --git a/Source/DXLookNFeel.cpp b/Source/DXLookNFeel.cpp index 26f3f1b..5febb6c 100644 --- a/Source/DXLookNFeel.cpp +++ b/Source/DXLookNFeel.cpp @@ -2,20 +2,20 @@ * * Copyright (c) 2013 Pascal Gauthier. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. */ #include "DXLookNFeel.h" diff --git a/Source/DXLookNFeel.h b/Source/DXLookNFeel.h index bdc85eb..296160a 100644 --- a/Source/DXLookNFeel.h +++ b/Source/DXLookNFeel.h @@ -2,20 +2,20 @@ * * Copyright (c) 2013 Pascal Gauthier. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. */ #ifndef DXLOOKNFEEL_H_INCLUDED diff --git a/Source/Dexed.h b/Source/Dexed.h index 6325b12..2929ae2 100644 --- a/Source/Dexed.h +++ b/Source/Dexed.h @@ -2,20 +2,20 @@ * * Copyright (c) 2014 Pascal Gauthier. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. */ #ifndef DEXED_H_INCLUDED diff --git a/Source/EngineMkI.cpp b/Source/EngineMkI.cpp index 832badc..c24020a 100644 --- a/Source/EngineMkI.cpp +++ b/Source/EngineMkI.cpp @@ -1,202 +1,123 @@ -/* - ============================================================================== - - EngineMkI.cpp - Created: 25 Aug 2014 12:08:00am - Author: Pascal Gauthier - - ============================================================================== -*/ +/** + * + * Copyright (c) 2014 Pascal Gauthier. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ #include "EngineMkI.h" #include #include -#include "sin.h" +#include "msfa/sin.h" +#include "msfa/exp2.h" - -void EngineMkI::compute(int32_t *output, FmOpParams *params, int algorithm, - int32_t *fb_buf, int feedback_shift, const Controllers *controllers) { - 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[0]; - int32_t gain2 = param.gain[1]; - /* - if (gain1 >= kLevelThresh || gain2 >= kLevelThresh) { - - if (!has_contents[outbus]) { - add = false; - } - - if (inbus == 0 || !has_contents[inbus]) { - // PG: this is my 'dirty' implementation of FB for 2 and 3 operators... - // still needs some tuning... - if ((flags & 0xc0) == 0xc0 && feedback_shift < 16) { - switch ( algorithm ) { - // two operator feedback, process exception for ALGO 6 - case 5 : - FmOpKernel::compute_fb2(outptr, params, fb_buf, feedback_shift); - param.phase += param.freq << LG_N; - params[1].phase += param.freq + params[1].freq << LG_N; // yuk, hack, we already processed op-5 - op++; // ignore next operator; - break; - // three operator feedback, process exception for ALGO 4 - case 3 : - FmOpKernel::compute_fb3(outptr, params, fb_buf, feedback_shift); - param.phase += param.freq << LG_N; - params[1].phase += param.freq + params[1].freq << LG_N; // hack, we already processed op-5 - op-4 - params[2].phase += param.freq + params[1].freq + params[2].freq << LG_N; // yuk yuk - op += 2; // ignore the 2 other operators - break; - default: - // one operator feedback, normal proces - //cout << "\t" << op << " fb " << inbus << outbus << add << endl; - FmOpKernel::compute_fb(outptr, param.phase, param.freq,gain1, gain2, fb_buf, feedback_shift, add); - param.phase += param.freq << LG_N; - break; - } - has_contents[outbus] = true; - continue; - } 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; - } -} -/* -void FmOpKernel::compute(int32_t *output, const int32_t *input, - int32_t phase0, int32_t freq, - int32_t gain1, int32_t gain2, bool add, const Controllers *controllers) { - 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 { +void EngineMkI::compute(int32_t *output, const int32_t *input, + int32_t phase0, int32_t freq, + int32_t gain1, int32_t gain2, bool add, const Controllers *controllers) { + int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; + int32_t gain = gain1; + int32_t phase = phase0; if (add) { - for (int i = 0; i < N; i++) { - gain += dgain; - int32_t y = Sin::lookup(phase + input[i]); - y &= controllers->sinBitFilter; - int32_t y1 = ((int64_t)y * (int64_t)gain) >> 24; - output[i] += y1; - phase += freq; - } + for (int i = 0; i < N; i++) { + gain += dgain; + int32_t y = Sin::lookup(phase + input[i]); + y &= controllers->sinBitFilter; + 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]); - y &= controllers->sinBitFilter; - int32_t y1 = ((int64_t)y * (int64_t)gain) >> 24; - output[i] = y1; - phase += freq; - } + for (int i = 0; i < N; i++) { + gain += dgain; + int32_t y = Sin::lookup(phase + input[i]); + y &= controllers->sinBitFilter; + 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, const Controllers *controllers) { - 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 { +void EngineMkI::compute_pure(int32_t *output, int32_t phase0, int32_t freq, + int32_t gain1, int32_t gain2, bool add, const Controllers *controllers) { + int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; + int32_t gain = gain1; + int32_t phase = phase0; if (add) { - for (int i = 0; i < N; i++) { - gain += dgain; - int32_t y = Sin::lookup(phase); - y &= controllers->sinBitFilter; - int32_t y1 = ((int64_t)y * (int64_t)gain) >> 24; - output[i] += y1; - phase += freq; - } + for (int i = 0; i < N; i++) { + gain += dgain; + int32_t y = Sin::lookup(phase); + y &= controllers->sinBitFilter; + 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); - y &= controllers->sinBitFilter; - int32_t y1 = ((int64_t)y * (int64_t)gain) >> 24; - output[i] = y1; - phase += freq; - } + for (int i = 0; i < N; i++) { + gain += dgain; + int32_t y = Sin::lookup(phase); + y &= controllers->sinBitFilter; + 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, const Controllers *controllers) { - 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 &= controllers->sinBitFilter; - 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 &= controllers->sinBitFilter; - y = ((int64_t)y * (int64_t)gain) >> 24; - output[i] = y; - phase += freq; +void EngineMkI::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, const Controllers *controllers) { + 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 &= controllers->sinBitFilter; + 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 &= controllers->sinBitFilter; + y = ((int64_t)y * (int64_t)gain) >> 24; + output[i] = y; + phase += freq; + } } - } - fb_buf[0] = y0; - fb_buf[1] = y; + fb_buf[0] = y0; + fb_buf[1] = y; } - +/* // exclusively used for ALGO 6 with feedback -void FmOpKernel::compute_fb2(int32_t *output, FmOpParams *parms, int32_t *fb_buf, int fb_shift, const Controllers *cont) { +void EngineMkI::compute_fb2(int32_t *output, FmOpParams *parms, int32_t *fb_buf, int fb_shift, const Controllers *cont) { int32_t dgain[2]; int32_t gain[2]; int32_t phase[2]; @@ -235,7 +156,7 @@ void FmOpKernel::compute_fb2(int32_t *output, FmOpParams *parms, int32_t *fb_buf } // exclusively used for ALGO 4 with feedback -void FmOpKernel::compute_fb3(int32_t *output, FmOpParams *parms, int32_t *fb_buf, int fb_shift, const Controllers *conts) { +void EngineMkI::compute_fb3(int32_t *output, FmOpParams *parms, int32_t *fb_buf, int fb_shift, const Controllers *conts) { int32_t dgain[3]; int32_t gain[3]; int32_t phase[3]; @@ -283,5 +204,79 @@ void FmOpKernel::compute_fb3(int32_t *output, FmOpParams *parms, int32_t *fb_buf fb_buf[0] = y0; fb_buf[1] = y; } +*/ + +void EngineMkI::render(int32_t *output, FmOpParams *params, int algorithm, + int32_t *fb_buf, int feedback_shift, const Controllers *controllers) { + 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]) { + // PG: this is my 'dirty' implementation of FB for 2 and 3 operators... + // still needs some tuning... + if ((flags & 0xc0) == 0xc0 && feedback_shift < 16) { + switch ( algorithm ) { + /* // two operator feedback, process exception for ALGO 6 + case 5 : + EngineMkI::compute_fb2(outptr, params, fb_buf, feedback_shift); + param.phase += param.freq << LG_N; + params[1].phase += param.freq + params[1].freq << LG_N; // yuk, hack, we already processed op-5 + op++; // ignore next operator; + break; + // three operator feedback, process exception for ALGO 4 + case 3 : + FmOpKernel::compute_fb3(outptr, params, fb_buf, feedback_shift); + param.phase += param.freq << LG_N; + params[1].phase += param.freq + params[1].freq << LG_N; // hack, we already processed op-5 - op-4 + params[2].phase += param.freq + params[1].freq + params[2].freq << LG_N; // yuk yuk + op += 2; // ignore the 2 other operators + break;*/ + default: + // one operator feedback, normal proces + //cout << "\t" << op << " fb " << inbus << outbus << add << endl; + compute_fb(outptr, param.phase, param.freq,gain1, gain2, fb_buf, feedback_shift, add, controllers); + param.phase += param.freq << LG_N; + break; + } + has_contents[outbus] = true; + continue; + } else { + // cout << op << " pure " << inbus << outbus << add << endl; + compute_pure(outptr, param.phase, param.freq, gain1, gain2, add, controllers); + } + + } else { + + // cout << op << " normal " << inbus << outbus << " " << param.freq << add << endl; + compute(outptr, buf_[inbus - 1].get(), + param.phase, param.freq, gain1, gain2, add, controllers); + } + + has_contents[outbus] = true; + + } else if (!add) { + has_contents[outbus] = false; + + } + param.phase += param.freq << LG_N; + } +} -*/ \ No newline at end of file diff --git a/Source/EngineMkI.h b/Source/EngineMkI.h index adddb50..67ee67e 100644 --- a/Source/EngineMkI.h +++ b/Source/EngineMkI.h @@ -1,12 +1,22 @@ -/* - ============================================================================== - - EngineMkI.h - Created: 25 Aug 2014 12:08:00am - Author: Pascal Gauthier - - ============================================================================== -*/ +/** + * + * Copyright (c) 2014 Pascal Gauthier. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ #ifndef ENGINEMKI_H_INCLUDED #define ENGINEMKI_H_INCLUDED @@ -20,12 +30,21 @@ class EngineMkI : public FmCore { public: - virtual void compute(int32_t *output, FmOpParams *params, int algorithm, - int32_t *fb_buf, int feedback_shift, const Controllers *controllers); + virtual void render(int32_t *output, FmOpParams *params, int algorithm, + int32_t *fb_buf, int feedback_shift, const Controllers *controllers); + + void compute(int32_t *output, const int32_t *input, int32_t phase0, int32_t freq, int32_t gain1, int32_t gain2, + bool add, const Controllers *controllers); + + void compute_pure(int32_t *output, int32_t phase0, int32_t freq, int32_t gain1, int32_t gain2, + bool add, const Controllers *controllers); + + 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, const Controllers *controllers); - static void compute_fb2(int32_t *output, FmOpParams *params, int32_t *fb_buf, int fb_shift); + void compute_fb2(int32_t *output, FmOpParams *params, int32_t *fb_buf, int fb_shift, const Controllers *controllers); - static void compute_fb3(int32_t *output, FmOpParams *params, int32_t *fb_buf, int fb_shift); + void compute_fb3(int32_t *output, FmOpParams *params, int32_t *fb_buf, int fb_shift, const Controllers *controllers); }; diff --git a/Source/EngineOpl.cpp b/Source/EngineOpl.cpp index e1e19fd..4443c61 100644 --- a/Source/EngineOpl.cpp +++ b/Source/EngineOpl.cpp @@ -1,31 +1,31 @@ - /* - * Copyright (C) 2014 Pascal Gauthier - * Copyright (C) 2012 Steffen Ohrendorf - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Original Java Code: Copyright (C) 2008 Robson Cozendey - * - * Some code based on forum posts in: http://forums.submarine.org.uk/phpBB/viewforum.php?f=9, - * Copyright (C) 2010-2013 by carbon14 and opl3 -*/ - -#include "PluginProcessor.h" +/* + * Copyright (C) 2014 Pascal Gauthier. + * Copyright (C) 2012 Steffen Ohrendorf + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Original Java Code: Copyright (C) 2008 Robson Cozendey + * + * Some code based on forum posts in: http://forums.submarine.org.uk/phpBB/viewforum.php?f=9, + * Copyright (C) 2010-2013 by carbon14 and opl3 + * + */ -const int32_t __attribute__ ((aligned(16))) zeros[N] = {0}; +#include "EngineOpl.h" +const int32_t __attribute__ ((aligned(16))) zeros[N] = {0}; uint16_t SignBit = 0x8000; @@ -80,11 +80,10 @@ inline uint16_t sinLog( uint16_t phi ) { case 0x0200: // rising quarter wave -ve Shape C return sinLogTable[index] | SignBit; - case 0x0300: + default: // falling quarter wave -ve Shape D return sinLogTable[index ^ 0xFF] | SignBit; } - return 0; } // 16 env units are ~3dB and halve the output @@ -95,7 +94,7 @@ inline uint16_t sinLog( uint16_t phi ) { * @warning @a env will not be checked for correct values. */ inline int16_t oplSin( uint16_t phase, uint16_t env ) { - uint16_t expVal = sinLog(phase) + (env << 3); + uint16_t expVal = sinLog(phase) + (env << 3); const bool isSigned = expVal & SignBit; expVal &= ~SignBit; @@ -113,61 +112,61 @@ inline int16_t oplSin( uint16_t phase, uint16_t env ) { } } -void EngineOpl::computeOpl(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; - const int32_t *adder = add ? output : zeros; - - for (int i = 0; i < N; i++) { - gain += dgain; - int32_t y = oplSin( (phase+input[i]) >> 14, gain1); - output[i] = (y << 15) + adder[i]; - phase += freq; - } +void EngineOpl::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; + const int32_t *adder = add ? output : zeros; + + for (int i = 0; i < N; i++) { + gain += dgain; + int32_t y = oplSin( (phase+input[i]) >> 14, gain); + output[i] = (y << 14) + adder[i]; + phase += freq; + } } -void EngineOpl::computeOpl_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; - const int32_t *adder = add ? output : zeros; - - for (int i = 0; i < N; i++) { - gain += dgain; - int32_t y = oplSin( phase >> 14, gain1); - output[i] = (y << 15) + adder[i]; - phase += freq; - } +void EngineOpl::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; + const int32_t *adder = add ? output : zeros; + + for (int i = 0; i < N; i++) { + gain += dgain; + int32_t y = oplSin( phase >> 14, gain); + output[i] = (y << 14) + adder[i]; + phase += freq; + } } -void EngineOpl::computeOpl_fb(int32_t *output, int32_t phase0, int32_t freq, +void EngineOpl::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; - const int32_t *adder = add ? output : zeros; + int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; + int32_t gain = gain1; + int32_t phase = phase0; + const int32_t *adder = add ? output : zeros; int32_t y0 = fb_buf[0]; int32_t y = fb_buf[1]; - for (int i = 0; i < N; i++) { - gain += dgain; + for (int i = 0; i < N; i++) { + gain += dgain; int32_t scaled_fb = (y0 + y) >> (fb_shift + 1); y0 = y; - int32_t y = oplSin( (phase+scaled_fb) >> 14, gain1); - output[i] = (y << 15) + adder[i]; - phase += freq; - } + int32_t y = oplSin( (phase+scaled_fb) >> 14, gain) << 14; + output[i] = y + adder[i]; + phase += freq; + } fb_buf[0] = y0; fb_buf[1] = y; } -void EngineOpl::compute(int32_t *output, FmOpParams *params, int algorithm, +void EngineOpl::render(int32_t *output, FmOpParams *params, int algorithm, int32_t *fb_buf, int feedback_shift, const Controllers *controllers) { - const int kLevelThresh = 505; // really ???? + const int kLevelThresh = 507; // really ???? const FmAlgorithm alg = algorithms[algorithm]; bool has_contents[3] = { true, false, false }; for (int op = 0; op < 6; op++) { @@ -177,8 +176,10 @@ void EngineOpl::compute(int32_t *output, FmOpParams *params, int algorithm, int inbus = (flags >> 4) & 3; int outbus = flags & 3; int32_t *outptr = (outbus == 0) ? output : buf_[outbus - 1].get(); - int32_t gain1 = 512-(param.level[0] >> 19); - int32_t gain2 = 512-(param.level[1] >> 19); + int32_t gain1 = param.gain_out == 0 ? 511 : param.gain_out; + int32_t gain2 = 512-(param.level_in >> 19); + param.gain_out = gain2; + if (gain1 <= kLevelThresh || gain2 <= kLevelThresh) { if (!has_contents[outbus]) { add = false; @@ -187,17 +188,17 @@ void EngineOpl::compute(int32_t *output, FmOpParams *params, int algorithm, // todo: more than one op in a feedback loop if ((flags & 0xc0) == 0xc0 && feedback_shift < 16) { // cout << op << " fb " << inbus << outbus << add << endl; - computeOpl_fb(outptr, param.phase, param.freq, + compute_fb(outptr, param.phase, param.freq, gain1, gain2, fb_buf, feedback_shift, add); } else { // cout << op << " pure " << inbus << outbus << add << endl; - computeOpl_pure(outptr, param.phase, param.freq, + compute_pure(outptr, param.phase, param.freq, gain1, gain2, add); } } else { // cout << op << " normal " << inbus << outbus << " " << param.freq << add << endl; - computeOpl(outptr, buf_[inbus - 1].get(), + compute(outptr, buf_[inbus - 1].get(), param.phase, param.freq, gain1, gain2, add); } has_contents[outbus] = true; diff --git a/Source/EngineOpl.h b/Source/EngineOpl.h index e9b2561..f614dc5 100644 --- a/Source/EngineOpl.h +++ b/Source/EngineOpl.h @@ -8,8 +8,8 @@ ============================================================================== */ -#ifndef EXTRAKERNELS_H_INCLUDED -#define EXTRAKERNELS_H_INCLUDED +#ifndef ENGINEOPL_H_INCLUDED +#define ENGINEOPL_H_INCLUDED #include "synth.h" #include "aligned_buf.h" @@ -20,15 +20,15 @@ class EngineOpl : public FmCore { public: - virtual void compute(int32_t *output, FmOpParams *params, int algorithm, + virtual void render(int32_t *output, FmOpParams *params, int algorithm, int32_t *fb_buf, int feedback_shift, const Controllers *controllers); - void computeOpl(int32_t *output, const int32_t *input, int32_t phase0, int32_t freq, int32_t gain1, int32_t gain2, bool add); - void computeOpl_pure(int32_t *output, int32_t phase0, int32_t freq, int32_t gain1, int32_t gain2, bool add); - void computeOpl_fb(int32_t *output, int32_t phase0, int32_t freq, + void compute(int32_t *output, const int32_t *input, int32_t phase0, int32_t freq, int32_t gain1, int32_t gain2, bool add); + void compute_pure(int32_t *output, int32_t phase0, int32_t freq, int32_t gain1, int32_t gain2, bool add); + 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 // EXTRAKERNELS_H_INCLUDED +#endif // ENGINEOPL_H_INCLUDED diff --git a/Source/PluginData.cpp b/Source/PluginData.cpp index cd850a1..b286d9d 100644 --- a/Source/PluginData.cpp +++ b/Source/PluginData.cpp @@ -2,20 +2,20 @@ * * Copyright (c) 2014 Pascal Gauthier. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. */ #include @@ -253,7 +253,7 @@ void DexedAudioProcessor::resetToInitVoice() { 99, 99, 99, 99, 99, 99, 99, 00, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 7, 99, 99, 99, 99, 99, 99, 99, 00, 39, 0, 0, 0, 0, 0, 0, 0, 99, 0, 1, 0, 7, 99, 99, 99, 99, 50, 50, 50, 50, 0, 0, 1, 35, 0, 0, 0, 1, 0, 3, 24, - 73, 78, 73, 84, 32, 86, 79, 73, 67, 69} ; + 73, 78, 73, 84, 32, 86, 79, 73, 67, 69 }; for(int i=0;igetDoubleAttribute("reso"); fx.uiGain = root->getDoubleAttribute("gain"); currentProgram = root->getIntAttribute("currentProgram"); - + + setEngineType(root->getIntAttribute("engineType", 0)); + monoMode = root->getIntAttribute("monoMode", 0); + XmlElement *dexedBlob = root->getChildByName("dexedBlob"); if ( dexedBlob == NULL ) { TRACE("dexedBlob element not found"); diff --git a/Source/PluginData.h b/Source/PluginData.h index 66c6f3b..710880f 100644 --- a/Source/PluginData.h +++ b/Source/PluginData.h @@ -2,20 +2,20 @@ * * Copyright (c) 2014 Pascal Gauthier. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. */ #ifndef PLUGINDATA_H_INCLUDED diff --git a/Source/PluginEditor.cpp b/Source/PluginEditor.cpp index 7724050..d8ea555 100644 --- a/Source/PluginEditor.cpp +++ b/Source/PluginEditor.cpp @@ -2,20 +2,20 @@ * * Copyright (c) 2013 Pascal Gauthier. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. */ #include "PluginProcessor.h" @@ -147,7 +147,7 @@ DexedAudioProcessorEditor::DexedAudioProcessorEditor (DexedAudioProcessor* owner initButton->addListener(this); initButton->setBounds(385, 6, 50, 18); - addAndMakeVisible(monoButton = new TextButton("MONO")); + addAndMakeVisible(monoButton = new ToggleButton("MONO")); monoButton->setButtonText("MONO"); monoButton->addListener(this); monoButton->setBounds(439, 6, 50, 18); @@ -213,6 +213,8 @@ DexedAudioProcessorEditor::DexedAudioProcessorEditor (DexedAudioProcessor* owner sendPopup.addItem(1, "Send program to DX7"); sendPopup.addItem(2, "Send cartridge to DX7"); + monoButton->setState(processor->isMonoMode() ? Button::ButtonState::buttonDown : Button::ButtonState::buttonNormal); + updateUI(); startTimer(100); } @@ -358,6 +360,12 @@ void DexedAudioProcessorEditor::buttonClicked(Button *buttonThatWasClicked) { return; } + if (buttonThatWasClicked == monoButton ) { + processor->setMonoMode(!processor->isMonoMode()); + monoButton->setState(processor->isMonoMode() ? Button::ButtonState::buttonDown : Button::ButtonState::buttonNormal); + return; + } + if (buttonThatWasClicked == aboutButton) { AboutBox about(this); about.runModalLoop(); diff --git a/Source/PluginEditor.h b/Source/PluginEditor.h index 06166da..a61cb1d 100644 --- a/Source/PluginEditor.h +++ b/Source/PluginEditor.h @@ -2,20 +2,19 @@ * * Copyright (c) 2013 Pascal Gauthier. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef PLUGINEDITOR_H_INCLUDED @@ -52,7 +51,7 @@ class DexedAudioProcessorEditor : public AudioProcessorEditor, ScopedPointer settingsButton; ScopedPointer sendButton; ScopedPointer initButton; - ScopedPointer monoButton; + ScopedPointer monoButton; ScopedPointer midiMonitor; void storeProgram(); diff --git a/Source/PluginFx.cpp b/Source/PluginFx.cpp index 4d9690d..9425bce 100644 --- a/Source/PluginFx.cpp +++ b/Source/PluginFx.cpp @@ -6,20 +6,20 @@ * Filter taken from the Obxd project : * https://github.com/2DaT/Obxd * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. */ #define _USE_MATH_DEFINES diff --git a/Source/PluginFx.h b/Source/PluginFx.h index 3c04d04..523301e 100644 --- a/Source/PluginFx.h +++ b/Source/PluginFx.h @@ -2,20 +2,20 @@ * * Copyright (c) 2013 Pascal Gauthier. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. */ #ifndef PLUGINFX_H_INCLUDED diff --git a/Source/PluginParam.cpp b/Source/PluginParam.cpp index c507b14..8e87339 100644 --- a/Source/PluginParam.cpp +++ b/Source/PluginParam.cpp @@ -2,20 +2,20 @@ * * Copyright (c) 2013 Pascal Gauthier. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. */ #include diff --git a/Source/PluginParam.h b/Source/PluginParam.h index 964cf68..051dced 100644 --- a/Source/PluginParam.h +++ b/Source/PluginParam.h @@ -2,20 +2,20 @@ * * Copyright (c) 2013 Pascal Gauthier. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. */ #ifndef PLUGINPARAM_H_INCLUDED diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index bb0c0ca..13dbc9a 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -2,20 +2,20 @@ * * Copyright (c) 2013 Pascal Gauthier. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. */ #include "PluginProcessor.h" @@ -55,7 +55,6 @@ DexedAudioProcessor::DexedAudioProcessor() { sendSysexChange = true; normalizeDxVelocity = false; sysexComm.listener = this; - keyboardState.addListener(&sysexComm); engineType = -1; memset(&voiceStatus, 0, sizeof(VoiceStatus)); @@ -148,9 +147,7 @@ void DexedAudioProcessor::processBlock(AudioSampleBuffer& buffer, MidiBuffer& mi refreshVoice = false; } - // Now pass any incoming midi messages to our keyboard state object, and let it - // add messages to the buffer if the user is clicking on the on-screen keys - keyboardState.processNextMidiBuffer (midiMessages, 0, numSamples, true); + keyboardState.processNextMidiBuffer(midiMessages, 0, numSamples, true); MidiBuffer::Iterator it(midiMessages); hasMidiMessage = it.getNextEvent(*nextMidi,midiEventPos); @@ -322,41 +319,85 @@ void DexedAudioProcessor::keydown(uint8_t pitch, uint8_t velo) { return; } - pitch += (data[144] - 24); + pitch += data[144] - 24; if ( normalizeDxVelocity ) { velo = ((float)velo) * 0.7874015; // 100/127 } int note = currentNote; - for (int i = 0; i < MAX_ACTIVE_NOTES; i++) { + for (int i=0; iinit(data, pitch, velo); - return; + break; } note = (note + 1) % MAX_ACTIVE_NOTES; } + + if ( monoMode ) { + for(int i=0; itransfertState(*voices[i].dx7_note); + break; + } + return; + } + } + } + voices[note].live = true; } void DexedAudioProcessor::keyup(uint8_t pitch) { - pitch += (data[144] - 24); + pitch += data[144] - 24; + + int note; + for (note=0; notekeyup(); + // note not found ? + if ( note == 16 ) { + TRACE("note-off not found???"); + return; + } + + if ( monoMode ) { + int highNote = -1; + int target = 0; + for (int i=0; i highNote ) { + target = i; + highNote = voices[i].midi_note; } - voices[note].keydown = false; } + + if ( highNote != -1 ) { + voices[note].live = false; + voices[target].live = true; + voices[target].dx7_note->transfertState(*voices[note].dx7_note); + } + } + + if ( sustain ) { + voices[note].sustained = true; + } else { + voices[note].dx7_note->keyup(); } } @@ -421,7 +462,6 @@ void DexedAudioProcessor::handleIncomingMidiMessage(MidiInput* source, const Mid forceRefreshUI = true; } - int DexedAudioProcessor::getEngineType() { return engineType; } @@ -443,6 +483,11 @@ void DexedAudioProcessor::setEngineType(int tp) { engineType = tp; } +void DexedAudioProcessor::setMonoMode(bool mode) { + panic(); + monoMode = mode; +} + // ==================================================================== bool DexedAudioProcessor::peekVoiceStatus() { if ( currentNote == -1 ) diff --git a/Source/PluginProcessor.h b/Source/PluginProcessor.h index 4d6d0bf..b999e44 100644 --- a/Source/PluginProcessor.h +++ b/Source/PluginProcessor.h @@ -2,20 +2,20 @@ * * Copyright (c) 2013 Pascal Gauthier. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. */ #ifndef PLUGINPROCESSOR_H_INCLUDED @@ -62,7 +62,8 @@ class DexedAudioProcessor : public AudioProcessor, public AsyncUpdater, public Lfo lfo; bool sustain; - + bool monoMode; + // Extra buffering for when GetSamples wants a buffer not a multiple of N float extra_buf[N]; int extra_buf_size; @@ -165,6 +166,10 @@ public : void releaseResources(); void processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages); void panic(); + bool isMonoMode() { + return monoMode; + } + void setMonoMode(bool mode); //============================================================================== AudioProcessorEditor* createEditor(); diff --git a/Source/SysexComm.cpp b/Source/SysexComm.cpp index d6f227a..77872a4 100644 --- a/Source/SysexComm.cpp +++ b/Source/SysexComm.cpp @@ -2,20 +2,20 @@ * * Copyright (c) 2014 Pascal Gauthier. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. */ #include "SysexComm.h" @@ -30,6 +30,7 @@ SysexComm::SysexComm() { input = NULL; output = NULL; + inputOutput = false; } SysexComm::~SysexComm() { @@ -51,7 +52,9 @@ bool SysexComm::setInput(String target) { input->stop(); delete input; input = NULL; + } + inputOutput = false; if ( listener == NULL ) return true; @@ -76,6 +79,10 @@ bool SysexComm::setInput(String target) { inputName = target; TRACE("sysex %s opened", target.toRawUTF8()); input->start(); + + if ( output ) + inputOutput = true; + return true; } @@ -88,6 +95,7 @@ bool SysexComm::setOutput(String target) { delete output; output = NULL; } + inputOutput = false; StringArray devices = MidiOutput::getDevices(); int idx = devices.indexOf(target); @@ -107,6 +115,10 @@ bool SysexComm::setOutput(String target) { } outputName = target; + + if ( input ) + inputOutput = true; + TRACE("sysex %s opened", target.toRawUTF8()); return true; } @@ -136,17 +148,11 @@ int SysexComm::send(const MidiMessage &message) { return 0; } -// This is called from the UI Keyboard... -void SysexComm::handleNoteOn(MidiKeyboardState*, int, int midiNoteNumber, float velocity) { - if ( output == NULL ) - return; +void SysexComm::playBuffer(MidiBuffer &keyboardEvents, int numSamples ) { + noteOutput.addEvents(keyboardEvents, 0, numSamples, 0); +} - outActivity = true; - char iVelo = velocity * 100; - MidiMessage msg(0x90 + sysexChl, midiNoteNumber, iVelo); - output->sendMessageNow(msg); +void SysexComm::handleAsyncUpdate() { + } -void SysexComm::handleNoteOff(MidiKeyboardState* source, int midiChannel, int midiNoteNumber) { - handleNoteOn(source, midiChannel, midiNoteNumber, 0); -} \ No newline at end of file diff --git a/Source/SysexComm.h b/Source/SysexComm.h index bc69f25..a825373 100644 --- a/Source/SysexComm.h +++ b/Source/SysexComm.h @@ -2,20 +2,20 @@ * * Copyright (c) 2014 Pascal Gauthier. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301 USA. */ #ifndef SYSEXCOMM_H_INCLUDED @@ -23,15 +23,20 @@ #include "../JuceLibraryCode/JuceHeader.h" -class SysexComm : public MidiKeyboardStateListener { +class SysexComm : public AsyncUpdater { MidiInput *input; MidiOutput *output; String inputName; String outputName; int sysexChl; - + + bool inputOutput; + + MidiBuffer noteOutput; public : MidiInputCallback *listener; + bool inActivity; + bool outActivity; SysexComm(); ~SysexComm(); @@ -46,14 +51,14 @@ public : bool isInputActive(); bool isOutputActive(); + inline bool isInputOutputActive() { + return inputOutput; + } int send(const MidiMessage& message); - - void handleNoteOn(MidiKeyboardState* source, int midiChannel, int midiNoteNumber, float velocity); - void handleNoteOff(MidiKeyboardState* source, int midiChannel, int midiNoteNumber); - - bool inActivity; - bool outActivity; + + void handleAsyncUpdate(); + void playBuffer(MidiBuffer &keyboardEvents, int numSamples); }; #endif // SYSEXCOMM_H_INCLUDED \ No newline at end of file diff --git a/Source/msfa/dx7note.cc b/Source/msfa/dx7note.cc index 5efff98..e62c903 100644 --- a/Source/msfa/dx7note.cc +++ b/Source/msfa/dx7note.cc @@ -170,8 +170,7 @@ void Dx7Note::init(const char patch[156], int midinote, int velocity) { basepitch_[op] = freq; // cout << op << " freq: " << freq << endl; params_[op].phase = 0; - params_[op].gain[1] = 0; - params_[op].level[1] = 0; + params_[op].gain_out = 0; ampmodsens_[op] = ampmodsenstab[patch[off + 14] & 3]; } for (int i = 0; i < 4; i++) { @@ -187,8 +186,7 @@ void Dx7Note::init(const char patch[156], int midinote, int velocity) { ampmoddepth_ = (patch[140] * 165) >> 6; } -void Dx7Note::compute(int32_t *buf, int32_t lfo_val, int32_t lfo_delay, - const Controllers *ctrls) { +void Dx7Note::compute(int32_t *buf, int32_t lfo_val, int32_t lfo_delay, const Controllers *ctrls) { int32_t pitchmod = pitchenv_.getsample(); uint32_t pmd = pitchmoddepth_ * lfo_delay; // Q32 // TODO(PG) : make this integer friendly @@ -214,29 +212,19 @@ void Dx7Note::compute(int32_t *buf, int32_t lfo_val, int32_t lfo_delay, pitchmod += pb; for (int op = 0; op < 6; op++) { - // PG: MEEEEEH, this needs to be cleanup. The amp mod is way better - // with the exp2 value than the original level that contains a fraction - // into the integer ? - // - // TODO: to clean up ! The AMD should be calculated on the level, not the gain - params_[op].gain[0] = params_[op].gain[1]; - params_[op].level[0] = params_[op].level[1]; - //int32_t gain = pow(2, 10 + level * (1.0 / (1 << 24))); params_[op].freq = Freqlut::lookup(basepitch_[op] + pitchmod); int32_t level = env_[op].getsample(); - params_[op].level[1] = level; - int32_t gain = Exp2::lookup(level - (14 * (1 << 24))); if (ampmodsens_[op] != 0) { - uint32_t sensamp = ((int64_t) ampmodsens_[op]) * ((int64_t) gain) >> 24; + /*uint32_t sensamp = ((int64_t) ampmodsens_[op]) * ((int64_t) gain) >> 24; sensamp = ((int64_t) sensamp) * ((int64_t) lfo_val) >> 24; uint32_t amd_level = (((int64_t) amd) * (int64_t) sensamp) >> 24; - gain -= amd_level; + gain -= amd_level;*/ } - params_[op].gain[1] = gain; + params_[op].level_in = level; } - ctrls->core->compute(buf, params_, algorithm_, fb_buf_, fb_shift_, ctrls); + ctrls->core->render(buf, params_, algorithm_, fb_buf_, fb_shift_, ctrls); } void Dx7Note::keyup() { @@ -266,10 +254,18 @@ void Dx7Note::update(const char patch[156], int midinote) { void Dx7Note::peekVoiceStatus(VoiceStatus &status) { for(int i=0;i<6;i++) { - status.amp[i] = params_[i].gain[1]; + 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 transfert voice state from different notes + */ +void Dx7Note::transfertState(Dx7Note &src) { + for (int i=0;i<6;i++) { + env_[i] = src.env_[i]; + } +} diff --git a/Source/msfa/dx7note.h b/Source/msfa/dx7note.h index c8774fa..a9e74a6 100644 --- a/Source/msfa/dx7note.h +++ b/Source/msfa/dx7note.h @@ -51,8 +51,9 @@ class Dx7Note { // PG:add the update void update(const char patch[156], int midinote); - void peekVoiceStatus(VoiceStatus &status); - + void peekVoiceStatus(VoiceStatus &status); + void transfertState(Dx7Note& src); + private: Env env_[6]; FmOpParams params_[6]; diff --git a/Source/msfa/env.cc b/Source/msfa/env.cc index 50b4b6c..2960096 100755 --- a/Source/msfa/env.cc +++ b/Source/msfa/env.cc @@ -19,12 +19,13 @@ #include "synth.h" #include "env.h" +#include "../Dexed.h" //using namespace std; uint32_t Env::sr_multiplier = (1<<24); void Env::init_sr(double sampleRate) { - sr_multiplier = (44100 / sampleRate) * (1<<23); + sr_multiplier = (44100.0 / sampleRate) * (1<<24); } void Env::init(const int r[4], const int l[4], int32_t ol, int rate_scaling) { @@ -106,10 +107,28 @@ void Env::advance(int newix) { inc_ = (4 + (qrate & 3)) << (2 + LG_N + (qrate >> 2)); // meh, this should be fixed elsewhere - inc_ = ((int64_t)inc_ * (int64_t)sr_multiplier) >> 23; + inc_ = ((int64_t)inc_ * (int64_t)sr_multiplier) >> 24; } } void Env::getPosition(char *step) { *step = ix_; } + +Env& Env::operator=(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_; + inc_ = src.inc_; + down_ = src.down_; + + return *this; +} + diff --git a/Source/msfa/env.h b/Source/msfa/env.h index f1e2af8..a57109e 100755 --- a/Source/msfa/env.h +++ b/Source/msfa/env.h @@ -45,6 +45,7 @@ class Env { void getPosition(char *step); static void init_sr(double sample_rate); + Env& operator=(Env &src); private: // PG: This code is normalized to 44100, need to put a multiplier diff --git a/Source/msfa/fm_core.cc b/Source/msfa/fm_core.cc index 8403ca6..29afb1e 100644 --- a/Source/msfa/fm_core.cc +++ b/Source/msfa/fm_core.cc @@ -19,6 +19,7 @@ #endif #include "synth.h" +#include "exp2.h" #include "fm_op_kernel.h" #include "fm_core.h" @@ -89,8 +90,8 @@ void FmCore::dump() { #endif } -void FmCore::compute(int32_t *output, FmOpParams *params, int algorithm, - int32_t *fb_buf, int feedback_shift, const Controllers *controller) { +void FmCore::render(int32_t *output, FmOpParams *params, int algorithm, + int32_t *fb_buf, int feedback_shift, const Controllers *controller) { const int kLevelThresh = 1120; const FmAlgorithm alg = algorithms[algorithm]; bool has_contents[3] = { true, false, false }; @@ -101,8 +102,10 @@ void FmCore::compute(int32_t *output, FmOpParams *params, int algorithm, int inbus = (flags >> 4) & 3; int outbus = flags & 3; int32_t *outptr = (outbus == 0) ? output : buf_[outbus - 1].get(); - int32_t gain1 = param.gain[0]; - int32_t gain2 = param.gain[1]; + 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; diff --git a/Source/msfa/fm_core.h b/Source/msfa/fm_core.h index e4c41bb..1eef6a9 100644 --- a/Source/msfa/fm_core.h +++ b/Source/msfa/fm_core.h @@ -48,7 +48,7 @@ class FmCore { public: virtual ~FmCore() {}; static void dump(); - virtual void compute(int32_t *output, FmOpParams *params, int algorithm, + virtual void render(int32_t *output, FmOpParams *params, int algorithm, int32_t *fb_buf, int32_t feedback_gain, const Controllers *controller); protected: AlignedBufbuf_[2]; diff --git a/Source/msfa/fm_op_kernel.h b/Source/msfa/fm_op_kernel.h index 794232d..c9739e5 100644 --- a/Source/msfa/fm_op_kernel.h +++ b/Source/msfa/fm_op_kernel.h @@ -18,12 +18,10 @@ #define __FM_OP_KERNEL_H struct FmOpParams { - int32_t gain[2]; + 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; - - // PG: temporary code, only useful for engine that already calculate the exp value - int32_t level[2]; }; class FmOpKernel {