Monophonic Mode support

pull/1/head
asb2m10 10 years ago
parent df045032ce
commit 97aeda47b7
  1. 2
      Builds/MacOSX/Dexed.xcodeproj/project.pbxproj
  2. BIN
      Builds/MacOSX/Dexed.xcodeproj/project.xcworkspace/xcuserdata/asb2m10.xcuserdatad/UserInterfaceState.xcuserstate
  3. 2
      Dexed.jucer
  4. 42
      README.md
  5. 26
      Source/DXComponents.cpp
  6. 24
      Source/DXComponents.h
  7. 24
      Source/DXLookNFeel.cpp
  8. 24
      Source/DXLookNFeel.h
  9. 24
      Source/Dexed.h
  10. 211
      Source/EngineMkI.cpp
  11. 43
      Source/EngineMkI.h
  12. 67
      Source/EngineOpl.cpp
  13. 14
      Source/EngineOpl.h
  14. 31
      Source/PluginData.cpp
  15. 24
      Source/PluginData.h
  16. 34
      Source/PluginEditor.cpp
  17. 25
      Source/PluginEditor.h
  18. 24
      Source/PluginFx.cpp
  19. 24
      Source/PluginFx.h
  20. 24
      Source/PluginParam.cpp
  21. 24
      Source/PluginParam.h
  22. 103
      Source/PluginProcessor.cpp
  23. 29
      Source/PluginProcessor.h
  24. 52
      Source/SysexComm.cpp
  25. 41
      Source/SysexComm.h
  26. 34
      Source/msfa/dx7note.cc
  27. 1
      Source/msfa/dx7note.h
  28. 23
      Source/msfa/env.cc
  29. 1
      Source/msfa/env.h
  30. 9
      Source/msfa/fm_core.cc
  31. 2
      Source/msfa/fm_core.h
  32. 6
      Source/msfa/fm_op_kernel.h

@ -892,8 +892,8 @@
0652CE27AE4971C99654E3BF = {isa = PBXGroup; children = (
8BADEB7BF1A65E83A7A1736D,
DC75DFCDFCDB425927B11EC0,
C222D35AC4FC5C2A3BB0F8B6,
8BEBEDCAD409EE3A5D383B6D,
C222D35AC4FC5C2A3BB0F8B6,
61F792AFE04C15F413A4F766,
7A58027CF8C6967B02370E01, ); name = dsp; sourceTree = "<group>"; };
427DD4218ED26D69B0149A90 = {isa = PBXGroup; children = (

@ -19,8 +19,8 @@
<GROUP id="{1B64F271-8E56-F19A-FF63-094159E5EF7B}" name="dsp">
<FILE id="bvvgdq" name="PluginFx.cpp" compile="1" resource="0" file="Source/PluginFx.cpp"/>
<FILE id="E4gace" name="PluginFx.h" compile="0" resource="0" file="Source/PluginFx.h"/>
<FILE id="Fyf1ag" name="EngineMkI.h" compile="0" resource="0" file="Source/EngineMkI.h"/>
<FILE id="gZfpcq" name="EngineMkI.cpp" compile="1" resource="0" file="Source/EngineMkI.cpp"/>
<FILE id="Fyf1ag" name="EngineMkI.h" compile="0" resource="0" file="Source/EngineMkI.h"/>
<FILE id="gY0vZ2" name="EngineOpl.cpp" compile="1" resource="0" file="Source/EngineOpl.cpp"/>
<FILE id="TF7JMc" name="EngineOpl.h" compile="0" resource="0" file="Source/EngineOpl.h"/>
</GROUP>

@ -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
-----------

@ -6,20 +6,20 @@
* Copyright (C) 2002 Juan Linietsky <coding@reduz.com.ar>
* Copyright (C) 2006 Mark-André Hopf <mhopf@mark13.org>
*
* 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) {

@ -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

@ -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"

@ -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

@ -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

@ -1,106 +1,37 @@
/*
==============================================================================
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 <math.h>
#include <cstdlib>
#include "sin.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 &param = 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);
}
#include "msfa/sin.h"
#include "msfa/exp2.h"
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,
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 (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;
@ -120,20 +51,14 @@ void FmOpKernel::compute(int32_t *output, const int32_t *input,
phase += freq;
}
}
}
}
void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq,
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 (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;
@ -153,13 +78,9 @@ void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq,
phase += freq;
}
}
}
}
#define noDOUBLE_ACCURACY
#define HIGH_ACCURACY
void FmOpKernel::compute_fb(int32_t *output, int32_t phase0, int32_t 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;
@ -194,9 +115,9 @@ void FmOpKernel::compute_fb(int32_t *output, int32_t phase0, int32_t freq,
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 &param = 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;
}
}

@ -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,
virtual void render(int32_t *output, FmOpParams *params, int algorithm,
int32_t *fb_buf, int feedback_shift, const Controllers *controllers);
static void compute_fb2(int32_t *output, FmOpParams *params, int32_t *fb_buf, int fb_shift);
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);
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);
};

@ -1,32 +1,32 @@
/*
* Copyright (C) 2014 Pascal Gauthier
/*
* Copyright (C) 2014 Pascal Gauthier.
* Copyright (C) 2012 Steffen Ohrendorf <steffen.ohrendorf@gmx.de>
*
* 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 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 library is distributed in the hope that it will be useful,
* 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
* Lesser General Public License for more details.
* 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 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
* 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 <robson@cozendey.com>
*
* 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"
#include "EngineOpl.h"
const int32_t __attribute__ ((aligned(16))) zeros[N] = {0};
uint16_t SignBit = 0x8000;
uint16_t sinLogTable[256] = {
@ -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
@ -113,7 +112,7 @@ 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) {
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;
@ -121,13 +120,13 @@ void EngineOpl::computeOpl(int32_t *output, const int32_t *input, int32_t phase0
for (int i = 0; i < N; i++) {
gain += dgain;
int32_t y = oplSin( (phase+input[i]) >> 14, gain1);
output[i] = (y << 15) + adder[i];
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) {
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;
@ -135,13 +134,13 @@ void EngineOpl::computeOpl_pure(int32_t *output, int32_t phase0, int32_t freq, i
for (int i = 0; i < N; i++) {
gain += dgain;
int32_t y = oplSin( phase >> 14, gain1);
output[i] = (y << 15) + adder[i];
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;
@ -155,8 +154,8 @@ void EngineOpl::computeOpl_fb(int32_t *output, int32_t phase0, int32_t freq,
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];
int32_t y = oplSin( (phase+scaled_fb) >> 14, gain) << 14;
output[i] = y + adder[i];
phase += freq;
}
@ -165,9 +164,9 @@ void EngineOpl::computeOpl_fb(int32_t *output, int32_t phase0, int32_t freq,
}
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;

@ -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

@ -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 <time.h>
@ -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;i<sizeof(init_voice);i++) {
data[i] = init_voice[i];
@ -277,6 +277,8 @@ void DexedAudioProcessor::getStateInformation(MemoryBlock& destData) {
dexedState.setAttribute("reso", fx.uiReso);
dexedState.setAttribute("gain", fx.uiGain);
dexedState.setAttribute("currentProgram", currentProgram);
dexedState.setAttribute("monoMode", monoMode);
dexedState.setAttribute("engineType", (int) engineType);
char sysex_blob[4104];
exportSysexCart((char *) &sysex_blob, (char *) sysex, 0);
@ -306,6 +308,9 @@ void DexedAudioProcessor::setStateInformation(const void* source, int sizeInByte
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");

@ -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

@ -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();

@ -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<TextButton> settingsButton;
ScopedPointer<TextButton> sendButton;
ScopedPointer<TextButton> initButton;
ScopedPointer<TextButton> monoButton;
ScopedPointer<ToggleButton> monoButton;
ScopedPointer<Component> midiMonitor;
void storeProgram();

@ -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

@ -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

@ -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 <time.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

@ -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,42 +319,86 @@ 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; i<MAX_ACTIVE_NOTES; i++) {
if (!voices[note].keydown) {
currentNote = (note + 1) % MAX_ACTIVE_NOTES;
lfo.keydown(); // TODO: should only do this if # keys down was 0
voices[note].midi_note = pitch;
voices[note].keydown = true;
voices[note].sustained = sustain;
voices[note].live = true;
voices[note].keydown = true;
voices[note].dx7_note->init(data, pitch, velo);
return;
break;
}
note = (note + 1) % MAX_ACTIVE_NOTES;
}
if ( monoMode ) {
for(int i=0; i<MAX_ACTIVE_NOTES; i++) {
if ( voices[i].live ) {
// all keys are up, don't transfert anything
if ( ! voices[i].keydown ) {
voices[i].live = false;
break;
}
if ( voices[i].midi_note < pitch ) {
voices[i].live = false;
voices[note].dx7_note->transfertState(*voices[i].dx7_note);
break;
}
return;
}
}
}
voices[note].live = true;
}
void DexedAudioProcessor::keyup(uint8_t pitch) {
pitch += (data[144] - 24);
pitch += data[144] - 24;
for (int note = 0; note < MAX_ACTIVE_NOTES; ++note) {
if (voices[note].midi_note == pitch && voices[note].keydown) {
if (sustain) {
int note;
for (note=0; note<MAX_ACTIVE_NOTES; ++note) {
if ( voices[note].midi_note == pitch && voices[note].keydown ) {
voices[note].keydown = false;
break;
}
}
// 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<MAX_ACTIVE_NOTES;i++) {
if ( voices[i].keydown && voices[i].midi_note > highNote ) {
target = i;
highNote = voices[i].midi_note;
}
}
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();
}
voices[note].keydown = false;
}
}
}
void DexedAudioProcessor::panic() {
@ -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 )

@ -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,6 +62,7 @@ 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];
@ -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();

@ -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;
outActivity = true;
char iVelo = velocity * 100;
MidiMessage msg(0x90 + sysexChl, midiNoteNumber, iVelo);
output->sendMessageNow(msg);
void SysexComm::playBuffer(MidiBuffer &keyboardEvents, int numSamples ) {
noteOutput.addEvents(keyboardEvents, 0, numSamples, 0);
}
void SysexComm::handleNoteOff(MidiKeyboardState* source, int midiChannel, int midiNoteNumber) {
handleNoteOn(source, midiChannel, midiNoteNumber, 0);
void SysexComm::handleAsyncUpdate() {
}

@ -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

@ -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];
}
}

@ -52,6 +52,7 @@ class Dx7Note {
// PG:add the update
void update(const char patch[156], int midinote);
void peekVoiceStatus(VoiceStatus &status);
void transfertState(Dx7Note& src);
private:
Env env_[6];

@ -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;
}

@ -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

@ -19,6 +19,7 @@
#endif
#include "synth.h"
#include "exp2.h"
#include "fm_op_kernel.h"
#include "fm_core.h"
@ -89,7 +90,7 @@ void FmCore::dump() {
#endif
}
void FmCore::compute(int32_t *output, FmOpParams *params, int algorithm,
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];
@ -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;

@ -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:
AlignedBuf<int32_t, N>buf_[2];

@ -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 {

Loading…
Cancel
Save