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. 121
      Source/PluginFx.cpp
  9. 2
      Source/PluginProcessor.cpp
  10. 24
      Source/msfa/dx7note.cc

@ -24,17 +24,18 @@ Features
Changelog Changelog
--------- ---------
#### Version 0.4.0 (current sprint) #### Version 0.4.0
* Modulation wheel support * Modulation wheel support
* Now using the [Obxd](https://obxd.wordpress.com) 4-pole lowpass filter implementation * Now using the [Obxd](https://obxd.wordpress.com) 4-pole lowpass filter implementation
* Pitchbend range / step * Pitchbend range / step
* Output VU status * Output/Volume VU status
Binary downloads Binary downloads
---------------- ----------------
Dexed is not a finished product but it is stable enough to be used in a DAW environment: 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. 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) * 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 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 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. 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 Credits & thanks
---------------- ----------------
* DX Synth engine : Raph Levien and the [msfa](https://code.google.com/p/music-synthesizer-for-android) team * 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) * Implement a better DX look and feel (amp, pitch, algo)
* Various code cleanup * Various code cleanup
* Standalone executable (for full support of the sysex editor) * Standalone executable (for full support of the sysex editor)
* Midi sample resolution on DAW block size
TODO - msfa 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) { void LcdDisplay::paint(Graphics &g) {
g.setColour(Colours::black.withAlpha(0.4f)); g.setColour(Colours::black.withAlpha(0.4f));
g.fillRoundedRectangle (0.0f, 0.0f, (float) getWidth(), (float) getHeight(), 1.0f); g.fillRoundedRectangle (0.0f, 0.0f, (float) getWidth(), (float) getHeight(), 1.0f);

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

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

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

@ -175,7 +175,6 @@ void DexedAudioProcessorEditor::buttonClicked(Button *buttonThatWasClicked) {
return; return;
} }
if (buttonThatWasClicked == loadButton) { if (buttonThatWasClicked == loadButton) {
FileChooser fc ("Import original DX sysex...", File::nonexistent, "*.syx;*.SYX;*.*", 1); 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.read((char *)syx_data, 4104);
fp_in.close(); fp_in.close();
processor->importSysex((char *) &syx_data); if ( processor->importSysex((char *) &syx_data) ) {
global.setSystemMessage(String("Unkown sysex format !?"));
}
processor->setCurrentProgram(0); processor->setCurrentProgram(0);
rebuildProgramCombobox(); rebuildProgramCombobox();
programs.setSelectedId(processor->getCurrentProgram()+1, NotificationType::dontSendNotification); programs.setSelectedId(processor->getCurrentProgram()+1, NotificationType::dontSendNotification);
@ -248,9 +249,6 @@ void DexedAudioProcessorEditor::buttonClicked(Button *buttonThatWasClicked) {
} }
if (buttonThatWasClicked == aboutButton) { 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); AboutBox about(this);
about.runModalLoop(); about.runModalLoop();
return; return;

@ -75,11 +75,10 @@ void PluginFx::init(int sr) {
uiCutoff = 1; uiCutoff = 1;
uiReso = 0; uiReso = 0;
uiGain = 0.8; uiGain = 1;
pCutoff = -1; pCutoff = -1;
pReso = -1; pReso = -1;
pGain = -1;
} }
inline float PluginFx::NR24(float sample,float g,float lpc) { 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) { 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 // don't apply the LPF if the cutoff is to maximum
if ( uiCutoff != 1 ) { if ( uiCutoff == 1 )
if ( uiCutoff != pCutoff || uiReso != pReso ) { return;
rReso = (0.991-logsc(1-uiReso,0,0.991));
R24 = 3.5 * rReso;
float cutoffNorm = logsc(uiCutoff,60,19000); if ( uiCutoff != pCutoff || uiReso != pReso ) {
rCutoff = (float)tan(cutoffNorm * sampleRateInv * juce::float_Pi); rReso = (0.991-logsc(1-uiReso,0,0.991));
R24 = 3.5 * rReso;
pCutoff = uiCutoff; float cutoffNorm = logsc(uiCutoff,60,19000);
pReso = uiReso; 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);
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;
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);
}
} }
if ( uiGain != pGain ) { // THIS IS MY FAVORITE 4POLE OBXd filter
rGain = linsc(uiGain, 0, 1.25);
pGain = uiGain; // 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);
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;
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;
}
for(int i=0; i < sampleSize; i++ ) //half volume comp
work[i] *= rGain; work[i] = mc * (1 + R24 * 0.45);
}
} }
/* /*

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

@ -26,6 +26,14 @@
using namespace std; 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) { int32_t midinote_to_logfreq(int midinote) {
const int base = 50857777; // (1 << 24) * (log(440) / log(2) - 69/12) const int base = 50857777; // (1 << 24) * (log(440) / log(2) - 69/12)
const int step = (1 << 24) / 12; const int step = (1 << 24) / 12;
@ -191,14 +199,16 @@ void Dx7Note::compute(int32_t *buf, int32_t lfo_val, int32_t lfo_delay,
pitchmod += (((int64_t)pmd) * (int64_t)senslfo) >> 39; pitchmod += (((int64_t)pmd) * (int64_t)senslfo) >> 39;
int pitchbend = ctrls->values_[kControllerPitch]; int pitchbend = ctrls->values_[kControllerPitch];
int32_t pb; int32_t pb = (pitchbend - 0x2000);
if ( ctrls->values_[kControllerPitchStep] == 0 ) { if ( pb != 0 ) {
pb = ((float)((pitchbend - 0x2000) << 11)) * ((float)ctrls->values_[kControllerPitchRange]) / 12.0; if ( ctrls->values_[kControllerPitchStep] == 0 ) {
} else { pb = ((float)(pb << 11)) * ((float)ctrls->values_[kControllerPitchRange]) / 12.0;
int stp = 12 / ctrls->values_[kControllerPitchStep]; } else {
pb = (pitchbend - 0x2000) / stp; int stp = 12 / ctrls->values_[kControllerPitchStep];
pb = (pb * stp) << 11; pb = pb * stp / 8191;
pb = (pb * (8191/stp)) << 11;
}
} }
pitchmod += pb; pitchmod += pb;

Loading…
Cancel
Save