Pitchbend step

pull/1/head
asb2m10 11 years ago
parent 3104d39f9f
commit e6f6ce0de1
  1. BIN
      Builds/MacOSX/Dexed.xcodeproj/project.xcworkspace/xcuserdata/asb2m10.xcuserdatad/UserInterfaceState.xcuserstate
  2. 12
      README.md
  3. 19
      Source/DXComponents.cpp
  4. 6
      Source/DXComponents.h
  5. 4
      Source/GlobalEditor.cpp
  6. 2
      Source/ParamDialog.cpp
  7. 8
      Source/PluginEditor.cpp
  8. 117
      Source/PluginFx.cpp
  9. 2
      Source/PluginProcessor.cpp
  10. 26
      Source/msfa/dx7note.cc

@ -24,17 +24,18 @@ Features
Changelog
---------
#### Version 0.4.0 (current sprint)
#### Version 0.4.0
* Modulation wheel support
* Now using the [Obxd](https://obxd.wordpress.com) 4-pole lowpass filter implementation
* Pitchbend range / step
* Output VU status
* Output/Volume VU status
Binary downloads
----------------
Dexed is not a finished product but it is stable enough to be used in a DAW environment:
in normal operation it shouldn't crash and the VST state saving works.
* Version 0.4.0 [vst win32](http://le-son666.com/software/dexed/dexed-0.4.0-win32.zip) - [vst win64](http://le-son666.com/software/dexed/dexed-0.4.0-win64.zip) - [vst os x](http://le-son666.com/software/dexed/dexed-0.4.0-osx.vst.zip)
* Version 0.3.0 [vst win32](http://le-son666.com/software/dexed/dexed-0.3.0-win32.zip) - [vst win64](http://le-son666.com/software/dexed/dexed-0.3.0-win64.zip) - [vst os x](http://le-son666.com/software/dexed/dexed-0.3.0-osx.vst.zip)
Using as a DX7 editor
@ -57,6 +58,12 @@ digital circuit bending feel.
Saving those corrupt/random sysex data will regenerate a 32 bulk program sysex dump with a
valid checksum for your DX7 keyboard. I'm in now way responsible if this breaks your DX7 keyboard.
FAQ (possibly)
--------------
* Some programs can generate distortion : This is because the voice summing still needs some tuning. You can simply lower the volume on those programs.
* Some sysex seems to be corrupted : Even if the sysex checksum doesn't match, Dexed will try to load it (this is a kind of randomize feature). Right now Dexed supports only original DX7 sysex, other DX family sysex (like the DX21) is considered as random data.
* Dexed doesn't receive/send parameter data from/to my DX7 : Most DX7 parameter change are done via sysex and very few VST host actually implements sysex. I'm planning to do a standalone executable to handle this issue.
Credits & thanks
----------------
* DX Synth engine : Raph Levien and the [msfa](https://code.google.com/p/music-synthesizer-for-android) team
@ -70,6 +77,7 @@ TODO - Dexed
* Implement a better DX look and feel (amp, pitch, algo)
* Various code cleanup
* Standalone executable (for full support of the sysex editor)
* Midi sample resolution on DAW block size
TODO - msfa
-----------

@ -437,6 +437,25 @@ void VuMeter::paint(Graphics &g) {
}
}
LcdDisplay::LcdDisplay() {
systemMsg << "*** DEXED FM synthesizer ***";
}
void LcdDisplay::timerCallback() {
systemMsg = "*** DEXED FM synthesizer ***";
repaint();
}
void LcdDisplay::setSystemMsg(String msg) {
systemMsg = msg;
triggerAsyncUpdate();
}
void LcdDisplay::handleAsyncUpdate() {
repaint();
startTimer(5000);
}
void LcdDisplay::paint(Graphics &g) {
g.setColour(Colours::black.withAlpha(0.4f));
g.fillRoundedRectangle (0.0f, 0.0f, (float) getWidth(), (float) getHeight(), 1.0f);

@ -56,8 +56,12 @@ public :
int totalBlocks;
};
class LcdDisplay : public Component {
class LcdDisplay : public Component, public Timer, public AsyncUpdater {
void timerCallback();
void handleAsyncUpdate();
public:
LcdDisplay();
void setSystemMsg(String msg);
String systemMsg;
String paramMsg;
void paint(Graphics &g);

@ -182,7 +182,6 @@ GlobalEditor::GlobalEditor ()
//[Constructor] You can add your own custom stuff here..
lcdDisplay->systemMsg << "*** DEXED FM synthesizer ***";
vuOutput->totalBlocks = 6;
//[/Constructor]
@ -448,8 +447,7 @@ void GlobalEditor::bind(DexedAudioProcessor *parent) {
}
void GlobalEditor::setSystemMessage(String msg) {
lcdDisplay->systemMsg = msg;
repaint();
lcdDisplay->setSystemMsg(msg);
}
void GlobalEditor::setParamMessage(String msg) {

@ -49,6 +49,7 @@ ParamDialog::ParamDialog ()
//[Constructor] You can add your own custom stuff here..
pitchRange->setEnabled(pitchStep->getValue() == 0);
//[/Constructor]
}
@ -110,6 +111,7 @@ void ParamDialog::sliderValueChanged (Slider* sliderThatWasMoved)
else if (sliderThatWasMoved == pitchStep)
{
//[UserSliderCode_pitchStep] -- add your slider handling code here..
pitchRange->setEnabled(pitchStep->getValue() == 0);
//[/UserSliderCode_pitchStep]
}

@ -175,7 +175,6 @@ void DexedAudioProcessorEditor::buttonClicked(Button *buttonThatWasClicked) {
return;
}
if (buttonThatWasClicked == loadButton) {
FileChooser fc ("Import original DX sysex...", File::nonexistent, "*.syx;*.SYX;*.*", 1);
@ -191,7 +190,9 @@ void DexedAudioProcessorEditor::buttonClicked(Button *buttonThatWasClicked) {
}
fp_in.read((char *)syx_data, 4104);
fp_in.close();
processor->importSysex((char *) &syx_data);
if ( processor->importSysex((char *) &syx_data) ) {
global.setSystemMessage(String("Unkown sysex format !?"));
}
processor->setCurrentProgram(0);
rebuildProgramCombobox();
programs.setSelectedId(processor->getCurrentProgram()+1, NotificationType::dontSendNotification);
@ -248,9 +249,6 @@ void DexedAudioProcessorEditor::buttonClicked(Button *buttonThatWasClicked) {
}
if (buttonThatWasClicked == aboutButton) {
/*AlertWindow::showMessageBoxAsync(AlertWindow::NoIcon, "DEXED - DX Emulator 0.4", "https://github.com/asb2m10/dexed\n"
"(c) 2013-2014 Pascal Gauthier\nUnder the GPL v2\n\n"
"Based on Music Synthesizer for Android\nhttps://code.google.com/p/music-synthesizer-for-android");*/
AboutBox about(this);
about.runModalLoop();
return;

@ -75,11 +75,10 @@ void PluginFx::init(int sr) {
uiCutoff = 1;
uiReso = 0;
uiGain = 0.8;
uiGain = 1;
pCutoff = -1;
pReso = -1;
pGain = -1;
}
inline float PluginFx::NR24(float sample,float g,float lpc) {
@ -96,74 +95,72 @@ inline float PluginFx::NR(float sample, float g) {
}
void PluginFx::process(float *work, int sampleSize) {
if ( uiGain != 1 ) {
for(int i=0; i < sampleSize; i++ )
work[i] *= uiGain;
}
// don't apply the LPF if the cutoff is to maximum
if ( uiCutoff != 1 ) {
if ( uiCutoff != pCutoff || uiReso != pReso ) {
rReso = (0.991-logsc(1-uiReso,0,0.991));
R24 = 3.5 * rReso;
if ( uiCutoff == 1 )
return;
if ( uiCutoff != pCutoff || uiReso != pReso ) {
rReso = (0.991-logsc(1-uiReso,0,0.991));
R24 = 3.5 * rReso;
float cutoffNorm = logsc(uiCutoff,60,19000);
rCutoff = (float)tan(cutoffNorm * sampleRateInv * juce::float_Pi);
pCutoff = uiCutoff;
pReso = uiReso;
float cutoffNorm = logsc(uiCutoff,60,19000);
rCutoff = (float)tan(cutoffNorm * sampleRateInv * juce::float_Pi);
R = 1 - rReso;
}
pCutoff = uiCutoff;
pReso = uiReso;
// THIS IS MY FAVORITE 4POLE OBXd filter
R = 1 - rReso;
}
// maybe smooth this value
float g = rCutoff;
float lpc = g / (1 + g);
// THIS IS MY FAVORITE 4POLE OBXd filter
for(int i=0; i < sampleSize; i++ ) {
float s = work[i];
s = s - 0.45*tptlpupw(c,s,15,sampleRateInv);
s = tptpc(d,s,bright);
float y0 = NR24(s,g,lpc);
//first low pass in cascade
double v = (y0 - s1) * lpc;
double res = v + s1;
s1 = res + v;
//damping
s1 =atan(s1*rcor24)*rcor24Inv;
float y1= res;
float y2 = tptpc(s2,y1,g);
float y3 = tptpc(s3,y2,g);
float y4 = tptpc(s4,y3,g);
float mc;
// maybe smooth this value
float g = rCutoff;
float lpc = g / (1 + g);
for(int i=0; i < sampleSize; i++ ) {
float s = work[i];
s = s - 0.45*tptlpupw(c,s,15,sampleRateInv);
s = tptpc(d,s,bright);
switch(mmch) {
case 0:
mc = ((1 - mmt) * y4 + (mmt) * y3);
break;
case 1:
mc = ((1 - mmt) * y3 + (mmt) * y2);
break;
case 2:
mc = ((1 - mmt) * y2 + (mmt) * y1);
break;
case 3:
mc = y1;
break;
}
float y0 = NR24(s,g,lpc);
//half volume comp
work[i] = mc * (1 + R24 * 0.45);
}
}
//first low pass in cascade
double v = (y0 - s1) * lpc;
double res = v + s1;
s1 = res + v;
//damping
s1 =atan(s1*rcor24)*rcor24Inv;
float y1= res;
float y2 = tptpc(s2,y1,g);
float y3 = tptpc(s3,y2,g);
float y4 = tptpc(s4,y3,g);
float mc;
if ( uiGain != pGain ) {
rGain = linsc(uiGain, 0, 1.25);
pGain = uiGain;
switch(mmch) {
case 0:
mc = ((1 - mmt) * y4 + (mmt) * y3);
break;
case 1:
mc = ((1 - mmt) * y3 + (mmt) * y2);
break;
case 2:
mc = ((1 - mmt) * y2 + (mmt) * y1);
break;
case 3:
mc = y1;
break;
}
//half volume comp
work[i] = mc * (1 + R24 * 0.45);
}
for(int i=0; i < sampleSize; i++ )
work[i] *= rGain;
}
/*

@ -63,7 +63,6 @@ DexedAudioProcessor::DexedAudioProcessor() {
controllers.values_[kControllerPitchRange] = 3;
controllers.values_[kControllerPitchStep] = 0;
loadPreference();
}
DexedAudioProcessor::~DexedAudioProcessor() {
@ -87,7 +86,6 @@ void DexedAudioProcessor::prepareToPlay(double sampleRate, int samplesPerBlock)
currentNote = 0;
controllers.values_[kControllerPitch] = 0x2000;
controllers.values_[kControllerModWheel] = 0;
sustain = false;
extra_buf_size = 0;

@ -26,6 +26,14 @@
using namespace std;
void dexed_trace(const char *source, const char *fmt, ...);
#ifdef _MSC_VER
#define TRACE(fmt, ...) dexed_trace(__FUNCTION__,fmt,##__VA_ARGS__)
#else
#define TRACE(fmt, ...) dexed_trace(__PRETTY_FUNCTION__,fmt,##__VA_ARGS__)
#endif
int32_t midinote_to_logfreq(int midinote) {
const int base = 50857777; // (1 << 24) * (log(440) / log(2) - 69/12)
const int step = (1 << 24) / 12;
@ -191,16 +199,18 @@ void Dx7Note::compute(int32_t *buf, int32_t lfo_val, int32_t lfo_delay,
pitchmod += (((int64_t)pmd) * (int64_t)senslfo) >> 39;
int pitchbend = ctrls->values_[kControllerPitch];
int32_t pb;
int32_t pb = (pitchbend - 0x2000);
if ( ctrls->values_[kControllerPitchStep] == 0 ) {
pb = ((float)((pitchbend - 0x2000) << 11)) * ((float)ctrls->values_[kControllerPitchRange]) / 12.0;
} else {
int stp = 12 / ctrls->values_[kControllerPitchStep];
pb = (pitchbend - 0x2000) / stp;
pb = (pb * stp) << 11;
if ( pb != 0 ) {
if ( ctrls->values_[kControllerPitchStep] == 0 ) {
pb = ((float)(pb << 11)) * ((float)ctrls->values_[kControllerPitchRange]) / 12.0;
} else {
int stp = 12 / ctrls->values_[kControllerPitchStep];
pb = pb * stp / 8191;
pb = (pb * (8191/stp)) << 11;
}
}
pitchmod += pb;
for (int op = 0; op < 6; op++) {
params_[op].gain[0] = params_[op].gain[1];

Loading…
Cancel
Save