Version 0.7a

pull/1/head
asb2m10 10 years ago
parent 97aeda47b7
commit 77f12fd001
  1. BIN
      Builds/MacOSX/Dexed.xcodeproj/project.xcworkspace/xcuserdata/asb2m10.xcuserdatad/UserInterfaceState.xcuserstate
  2. 6
      README.md
  3. 161
      Source/EngineMkI.cpp
  4. 33
      Source/EngineMkI.h
  5. 2
      Source/EngineOpl.cpp
  6. 2
      Source/PluginEditor.cpp
  7. 5
      Source/PluginProcessor.cpp
  8. 18
      Source/msfa/dx7note.cc
  9. 4
      Source/msfa/env.cc
  10. 2
      Source/msfa/env.h

@ -37,12 +37,13 @@ Changelog
#### Version 0.7.0 (current sprint)
* Preliminary Algo 4 & 6 feedback support
* DX Engine 'Dirty DX' emulation, including one based on OPL chips
* DX Engine LFO amplitude. This still needs some tunings :(
* DX Engine LFO amplitude. This still needs tuning.
* Monophonic mode
* Added the 'INIT' button to re-initialize a program
* 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
* The DX7 Sysex port are now only used for sysex messages. This is to avoid any midi note feedback.
#### Version 0.6.1
* Mouse over + LFO type fix + pitch eg values
@ -146,4 +147,5 @@ TODO - Dexed
TODO - msfa
-----------
* Portamento implementation
* Feedback tuning
* Better Amplitude Modulation
* Test maximum delay lfo values that seems to be reset

@ -1,21 +1,18 @@
/**
*
* 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.
/*
* Copyright 2014 Pascal Gauthier.
* Copyright 2012 Google Inc.
*
* 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.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "EngineMkI.h"
@ -26,6 +23,41 @@
#include "msfa/sin.h"
#include "msfa/exp2.h"
const FmAlgorithm EngineMkI::algo2[32] = {
{ { 0xc1, 0x11, 0x11, 0x14, 0x01, 0x14 } }, // 1
{ { 0x01, 0x11, 0x11, 0x14, 0xc1, 0x14 } }, // 2
{ { 0xc1, 0x11, 0x14, 0x01, 0x11, 0x14 } }, // 3
{ { 0xc4, 0x00, 0x00, 0x01, 0x11, 0x14 } }, // 4 ** EXCEPTION VIA CODE
{ { 0xc1, 0x14, 0x01, 0x14, 0x01, 0x14 } }, // 5
{ { 0xc4, 0x00, 0x01, 0x14, 0x01, 0x14 } }, // 6 ** EXCEPTION VIA CODE
{ { 0xc1, 0x11, 0x05, 0x14, 0x01, 0x14 } }, // 7
{ { 0x01, 0x11, 0xc5, 0x14, 0x01, 0x14 } }, // 8
{ { 0x01, 0x11, 0x05, 0x14, 0xc1, 0x14 } }, // 9
{ { 0x01, 0x05, 0x14, 0xc1, 0x11, 0x14 } }, // 10
{ { 0xc1, 0x05, 0x14, 0x01, 0x11, 0x14 } }, // 11
{ { 0x01, 0x05, 0x05, 0x14, 0xc1, 0x14 } }, // 12
{ { 0xc1, 0x05, 0x05, 0x14, 0x01, 0x14 } }, // 13
{ { 0xc1, 0x05, 0x11, 0x14, 0x01, 0x14 } }, // 14
{ { 0x01, 0x05, 0x11, 0x14, 0xc1, 0x14 } }, // 15
{ { 0xc1, 0x11, 0x02, 0x25, 0x05, 0x14 } }, // 16
{ { 0x01, 0x11, 0x02, 0x25, 0xc5, 0x14 } }, // 17
{ { 0x01, 0x11, 0x11, 0xc5, 0x05, 0x14 } }, // 18
{ { 0xc1, 0x14, 0x14, 0x01, 0x11, 0x14 } }, // 19
{ { 0x01, 0x05, 0x14, 0xc1, 0x14, 0x14 } }, // 20
{ { 0x01, 0x14, 0x14, 0xc1, 0x14, 0x14 } }, // 21
{ { 0xc1, 0x14, 0x14, 0x14, 0x01, 0x14 } }, // 22
{ { 0xc1, 0x14, 0x14, 0x01, 0x14, 0x04 } }, // 23
{ { 0xc1, 0x14, 0x14, 0x14, 0x04, 0x04 } }, // 24
{ { 0xc1, 0x14, 0x14, 0x04, 0x04, 0x04 } }, // 25
{ { 0xc1, 0x05, 0x14, 0x01, 0x14, 0x04 } }, // 26
{ { 0x01, 0x05, 0x14, 0xc1, 0x14, 0x04 } }, // 27
{ { 0x04, 0xc1, 0x11, 0x14, 0x01, 0x14 } }, // 28
{ { 0xc1, 0x14, 0x01, 0x14, 0x04, 0x04 } }, // 29
{ { 0x04, 0xc1, 0x11, 0x14, 0x04, 0x04 } }, // 30
{ { 0xc1, 0x14, 0x04, 0x04, 0x04, 0x04 } }, // 31
{ { 0xc4, 0x04, 0x04, 0x04, 0x04, 0x04 } }, // 32
};
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) {
@ -115,9 +147,9 @@ void EngineMkI::compute_fb(int32_t *output, int32_t phase0, int32_t freq,
fb_buf[1] = y;
}
/*
// exclusively used for ALGO 6 with feedback
void EngineMkI::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 gain01, int32_t gain02, int32_t *fb_buf, int fb_shift, const Controllers *cont) {
int32_t dgain[2];
int32_t gain[2];
int32_t phase[2];
@ -127,27 +159,29 @@ void EngineMkI::compute_fb2(int32_t *output, FmOpParams *parms, int32_t *fb_buf,
phase[0] = parms[0].phase;
phase[1] = parms[1].phase;
dgain[0] = (parms[0].gain[1] - parms[0].gain[0] + (N >> 1)) >> LG_N;
dgain[1] = (parms[1].gain[1] - parms[1].gain[0] + (N >> 1)) >> LG_N;
gain[0] = gain01;
gain[1] = parms[1].gain_out;
gain[0] = parms[0].gain[0];
gain[1] = parms[1].gain[1];
dgain[0] = (gain02 - gain01 + (N >> 1)) >> LG_N;
parms[1].gain_out = Exp2::lookup(parms[1].level_in - (14 * (1 << 24)));
dgain[1] = (parms[1].gain_out - gain[1] + (N >> 1)) >> LG_N;
for (int i = 0; i < N; i++) {
// op 0
gain[0] += dgain[0];
int32_t scaled_fb = (y0 + y) >> (fb_shift + 1);
int32_t scaled_fb = (y0 + y) >> (fb_shift + 2); // tsk tsk tsk: this needs some tuning
y0 = y;
y = Sin::lookup(phase[0] + scaled_fb);
y = ((int64_t)y * (int64_t)gain) >> 24;
y &= cont->sinBitFilter;
y = ((int64_t)y * (int64_t)gain[0]) >> 24;
phase[0] += parms[0].freq;
// op 1
gain[1] += dgain[1];
scaled_fb = (y0 + y) >> (fb_shift + 1);
y0 = y;
y = Sin::lookup(phase[1] + scaled_fb + y);
y = ((int64_t)y * (int64_t)gain) >> 24;
y = Sin::lookup(phase[1] + y);
y &= cont->sinBitFilter;
y = ((int64_t)y * (int64_t)gain[1]) >> 24;
output[i] = y;
phase[1] += parms[1].freq;
}
@ -156,7 +190,7 @@ void EngineMkI::compute_fb2(int32_t *output, FmOpParams *parms, int32_t *fb_buf,
}
// exclusively used for ALGO 4 with feedback
void EngineMkI::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 gain01, int32_t gain02, int32_t *fb_buf, int fb_shift, const Controllers *cont) {
int32_t dgain[3];
int32_t gain[3];
int32_t phase[3];
@ -166,50 +200,52 @@ void EngineMkI::compute_fb3(int32_t *output, FmOpParams *parms, int32_t *fb_buf,
phase[0] = parms[0].phase;
phase[1] = parms[1].phase;
phase[2] = parms[2].phase;
gain[0] = gain01;
gain[1] = parms[1].gain_out;
gain[2] = parms[2].gain_out;
dgain[0] = (parms[0].gain[1] - parms[0].gain[0] + (N >> 1)) >> LG_N;
dgain[1] = (parms[1].gain[1] - parms[1].gain[0] + (N >> 1)) >> LG_N;
dgain[2] = (parms[2].gain[1] - parms[2].gain[0] + (N >> 1)) >> LG_N;
dgain[0] = (gain02 - gain01 + (N >> 1)) >> LG_N;
gain[0] = parms[0].gain[0];
gain[1] = parms[1].gain[0];
gain[2] = parms[2].gain[0];
parms[1].gain_out = Exp2::lookup(parms[1].level_in - (14 * (1 << 24)));
dgain[1] = (parms[1].gain_out - gain[1] + (N >> 1)) >> LG_N;
parms[2].gain_out = Exp2::lookup(parms[2].level_in - (14 * (1 << 24)));
dgain[2] = (parms[1].gain_out - gain[2] + (N >> 1)) >> LG_N;
for (int i = 0; i < N; i++) {
// op 0
gain[0] += dgain[0];
int32_t scaled_fb = (y0 + y) >> (fb_shift + 1);
int32_t scaled_fb = (y0 + y) >> (fb_shift + 6); // tsk tsk tsk: this needs some tuning
y0 = y;
y = Sin::lookup(phase[0] + scaled_fb);
y = ((int64_t)y * (int64_t)gain) >> 24;
y &= cont->sinBitFilter;
y = ((int64_t)y * (int64_t)gain[0]) >> 24;
phase[0] += parms[0].freq;
// op 1
gain[1] += dgain[1];
scaled_fb = (y0 + y) >> (fb_shift + 1);
y0 = y;
y = Sin::lookup(phase[1] + scaled_fb + y);
y = ((int64_t)y * (int64_t)gain) >> 24;
y = Sin::lookup(phase[1] + y);
y &= cont->sinBitFilter;
y = ((int64_t)y * (int64_t)gain[1]) >> 24;
phase[1] += parms[1].freq;
// op 2
gain[2] += dgain[2];
scaled_fb = (y0 + y) >> (fb_shift + 1);
y0 = y;
y = Sin::lookup(phase[2] + scaled_fb + y);
y = ((int64_t)y * (int64_t)gain) >> 24;
y = Sin::lookup(phase[2] + y);
y &= cont->sinBitFilter;
y = ((int64_t)y * (int64_t)gain[2]) >> 24;
output[i] = y;
phase[2] += parms[2].freq;
}
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];
const FmAlgorithm alg = algo2[algorithm];
bool has_contents[3] = { true, false, false };
for (int op = 0; op < 6; op++) {
@ -234,35 +270,29 @@ void EngineMkI::render(int32_t *output, FmOpParams *params, int algorithm,
// 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;*/
// two operator feedback, process exception for ALGO 6
case 5 :
compute_fb2(outptr, params, gain1, gain2, fb_buf, feedback_shift, controllers);
params[1].phase += 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 :
compute_fb3(outptr, params, gain1, gain2, fb_buf, feedback_shift, controllers);
params[1].phase += params[1].freq << LG_N; // hack, we already processed op-5 - op-4
params[2].phase += 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;
@ -274,7 +304,6 @@ void EngineMkI::render(int32_t *output, FmOpParams *params, int algorithm,
} else if (!add) {
has_contents[outbus] = false;
}
param.phase += param.freq << LG_N;
}

@ -1,21 +1,18 @@
/**
/*
* Copyright 2014 Pascal Gauthier.
* Copyright 2012 Google Inc.
*
* Copyright (c) 2014 Pascal Gauthier.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ENGINEMKI_H_INCLUDED
@ -29,6 +26,8 @@
class EngineMkI : public FmCore {
//refacter this when it is working
const static FmAlgorithm algo2[32];
public:
virtual void render(int32_t *output, FmOpParams *params, int algorithm,
int32_t *fb_buf, int feedback_shift, const Controllers *controllers);
@ -42,9 +41,9 @@ public:
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);
void compute_fb2(int32_t *output, FmOpParams *params, int32_t gain01, int32_t gain02, int32_t *fb_buf, int fb_shift, const Controllers *controllers);
void compute_fb3(int32_t *output, FmOpParams *params, int32_t *fb_buf, int fb_shift, const Controllers *controllers);
void compute_fb3(int32_t *output, FmOpParams *params, int32_t gain01, int32_t gain02, int32_t *fb_buf, int fb_shift, const Controllers *controllers);
};

@ -154,7 +154,7 @@ void EngineOpl::compute_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, gain) << 14;
y = oplSin( (phase+scaled_fb) >> 14, gain) << 14;
output[i] = y + adder[i];
phase += freq;
}

@ -361,7 +361,7 @@ void DexedAudioProcessorEditor::buttonClicked(Button *buttonThatWasClicked) {
}
if (buttonThatWasClicked == monoButton ) {
processor->setMonoMode(!processor->isMonoMode());
processor->setMonoMode(monoButton->getToggleState());
monoButton->setState(processor->isMonoMode() ? Button::ButtonState::buttonDown : Button::ButtonState::buttonNormal);
return;
}

@ -185,6 +185,7 @@ void DexedAudioProcessor::processBlock(AudioSampleBuffer& buffer, MidiBuffer& mi
}
int32_t lfovalue = lfo.getsample();
int32_t lfodelay = lfo.getdelay();
for (int note = 0; note < MAX_ACTIVE_NOTES; ++note) {
if (voices[note].live) {
voices[note].dx7_note->compute(audiobuf.get(), lfovalue, lfodelay, &controllers);
@ -372,7 +373,7 @@ void DexedAudioProcessor::keyup(uint8_t pitch) {
}
// note not found ?
if ( note == 16 ) {
if ( note >= MAX_ACTIVE_NOTES ) {
TRACE("note-off not found???");
return;
}
@ -381,7 +382,7 @@ void DexedAudioProcessor::keyup(uint8_t pitch) {
int highNote = -1;
int target = 0;
for (int i=0; i<MAX_ACTIVE_NOTES;i++) {
if ( voices[i].keydown && voices[i].midi_note > highNote ) {
if ( voices[i].keydown && voices[i].midi_note > highNote ) {
target = i;
highNote = voices[i].midi_note;
}

@ -192,8 +192,10 @@ void Dx7Note::compute(int32_t *buf, int32_t lfo_val, int32_t lfo_delay, const Co
// TODO(PG) : make this integer friendly
uint32_t pwmd = (ctrls->values_[kControllerModWheel] * 0.7874) * (1 << 24);
int32_t senslfo = pitchmodsens_ * (lfo_val - (1 << 23));
uint32_t amd = ((int64_t) ampmoddepth_ * (int64_t) lfo_delay) >> 8; // Q24 :D
amd = ((int64_t) amd * (int64_t) lfo_val) >> 24;
pitchmod += (((int64_t) pwmd) * (int64_t) senslfo) >> 39;
pitchmod += (((int64_t) pmd) * (int64_t) senslfo) >> 39;
@ -217,10 +219,12 @@ void Dx7Note::compute(int32_t *buf, int32_t lfo_val, int32_t lfo_delay, const Co
int32_t level = env_[op].getsample();
if (ampmodsens_[op] != 0) {
/*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;*/
uint32_t sensamp = ((uint64_t) amd) * ((uint64_t) ampmodsens_[op]) >> 24;
// TODO: mehhh.. this needs some real tuning.
uint32_t pt = exp(((float)sensamp)/262144 * 0.07 + 12.2);
uint32_t ldiff = ((uint64_t)level) * (((uint64_t)pt<<4)) >> 28;
level -= ldiff;
}
params_[op].level_in = level;
}
@ -265,7 +269,9 @@ void Dx7Note::peekVoiceStatus(VoiceStatus &status) {
*/
void Dx7Note::transfertState(Dx7Note &src) {
for (int i=0;i<6;i++) {
env_[i] = src.env_[i];
env_[i].transfert(src.env_[i]);
params_[i].gain_out = src.params_[i].gain_out;
}
}

@ -115,7 +115,7 @@ void Env::getPosition(char *step) {
*step = ix_;
}
Env& Env::operator=(Env &src) {
void Env::transfert(Env &src) {
for(int i=0;i<4;i++) {
rates_[i] = src.rates_[i];
levels_[i] = src.levels_[i];
@ -128,7 +128,5 @@ Env& Env::operator=(Env &src) {
ix_ = src.ix_;
inc_ = src.inc_;
down_ = src.down_;
return *this;
}

@ -45,7 +45,7 @@ class Env {
void getPosition(char *step);
static void init_sr(double sample_rate);
Env& operator=(Env &src);
void transfert(Env &src);
private:
// PG: This code is normalized to 44100, need to put a multiplier

Loading…
Cancel
Save