Storing programs

pull/1/head
asb2m10 11 years ago
parent 7211900796
commit 26f049653b
  1. BIN
      Builds/MacOSX/Dexed.xcodeproj/project.xcworkspace/xcuserdata/asb2m10.xcuserdatad/UserInterfaceState.xcuserstate
  2. 96
      Source/OperatorEditor.cpp
  3. 94
      Source/PluginEditor.cpp
  4. 2
      Source/PluginEditor.h
  5. 70
      Source/PluginFx.cpp
  6. 81
      Source/PluginParam.cpp
  7. 9
      Source/PluginProcessor.h

@ -360,13 +360,13 @@ void OperatorEditor::sliderValueChanged (Slider* sliderThatWasMoved)
else if (sliderThatWasMoved == opFine)
{
//[UserSliderCode_opFine] -- add your slider handling code here..
updateDisplay();
updateDisplay();
//[/UserSliderCode_opFine]
}
else if (sliderThatWasMoved == opCoarse)
{
//[UserSliderCode_opCoarse] -- add your slider handling code here..
updateDisplay();
updateDisplay();
//[/UserSliderCode_opCoarse]
}
else if (sliderThatWasMoved == gain)
@ -377,7 +377,7 @@ void OperatorEditor::sliderValueChanged (Slider* sliderThatWasMoved)
else if (sliderThatWasMoved == detune)
{
//[UserSliderCode_detune] -- add your slider handling code here..
updateDisplay();
updateDisplay();
//[/UserSliderCode_detune]
}
else if (sliderThatWasMoved == sclLeftLevel)
@ -423,7 +423,7 @@ void OperatorEditor::comboBoxChanged (ComboBox* comboBoxThatHasChanged)
if (comboBoxThatHasChanged == opMode)
{
//[UserComboBoxCode_opMode] -- add your combo box handling code here..
updateDisplay();
updateDisplay();
//[/UserComboBoxCode_opMode]
}
else if (comboBoxThatHasChanged == kbdLeftCurve)
@ -445,30 +445,30 @@ void OperatorEditor::comboBoxChanged (ComboBox* comboBoxThatHasChanged)
//[MiscUserCode] You can add your own definitions of your custom methods or any other code here...
void OperatorEditor::bind(DexedAudioProcessor *parent, int op) {
int targetNum = op+1;
int targetNum = op+1;
String opName;
opName << "OP" << targetNum;
opId->setText(opName, NotificationType::dontSendNotification);
parent->opCtrl[op].egLevel[0]->bind(s_egl1);
parent->opCtrl[op].egLevel[1]->bind(s_egl2);
parent->opCtrl[op].egLevel[2]->bind(s_egl3);
parent->opCtrl[op].egLevel[3]->bind(s_egl4);
parent->opCtrl[op].egRate[0]->bind(s_egv1);
parent->opCtrl[op].egRate[1]->bind(s_egv2);
parent->opCtrl[op].egRate[2]->bind(s_egv3);
parent->opCtrl[op].egRate[3]->bind(s_egv4);
parent->opCtrl[op].level->bind(opLevel);
parent->opCtrl[op].opMode->bind(opMode);
parent->opCtrl[op].fine->bind(opFine);
parent->opCtrl[op].coarse->bind(opCoarse);
parent->opCtrl[op].detune->bind(detune);
parent->opCtrl[op].sclBrkPt->bind(sclLvlBrkPt);
parent->opCtrl[op].sclLeftCurve->bind(kbdLeftCurve);
parent->opCtrl[op].sclRightCurve->bind(kbdRightCurve);
parent->opCtrl[op].sclLeftDepth->bind(sclLeftLevel);
parent->opCtrl[op].sclRightDepth->bind(sclRightLevel);
opId->setText(opName, NotificationType::dontSendNotification);
parent->opCtrl[op].egLevel[0]->bind(s_egl1);
parent->opCtrl[op].egLevel[1]->bind(s_egl2);
parent->opCtrl[op].egLevel[2]->bind(s_egl3);
parent->opCtrl[op].egLevel[3]->bind(s_egl4);
parent->opCtrl[op].egRate[0]->bind(s_egv1);
parent->opCtrl[op].egRate[1]->bind(s_egv2);
parent->opCtrl[op].egRate[2]->bind(s_egv3);
parent->opCtrl[op].egRate[3]->bind(s_egv4);
parent->opCtrl[op].level->bind(opLevel);
parent->opCtrl[op].opMode->bind(opMode);
parent->opCtrl[op].fine->bind(opFine);
parent->opCtrl[op].coarse->bind(opCoarse);
parent->opCtrl[op].detune->bind(detune);
parent->opCtrl[op].sclBrkPt->bind(sclLvlBrkPt);
parent->opCtrl[op].sclLeftCurve->bind(kbdLeftCurve);
parent->opCtrl[op].sclRightCurve->bind(kbdRightCurve);
parent->opCtrl[op].sclLeftDepth->bind(sclLeftLevel);
parent->opCtrl[op].sclRightDepth->bind(sclRightLevel);
parent->opCtrl[op].sclRate->bind(sclRateScaling);
}
@ -481,32 +481,32 @@ void OperatorEditor::updateGain(float v) {
void OperatorEditor::updateDisplay() {
float freq = opCoarse->getValue();
float fine = opFine->getValue();
String txtFreq;
if (opMode->getSelectedItemIndex() == 0) {
if ( freq == 0 )
freq = 0.5;
txtFreq << "f = " << (freq + ((freq*2) * (fine/100)));
} else {
freq = pow(10,((int)freq)&3);
freq = freq + ((freq*10) * (fine/100));
txtFreq << freq << " Hz";
}
int det = detune->getValue() - 7;
if ( det != 0 ) {
if ( det > 0 )
txtFreq << " +" << det;
else
txtFreq << " " << det;
}
khzDisplay->setText(txtFreq, NotificationType::dontSendNotification);
envDisplay->repaint();
String txtFreq;
if (opMode->getSelectedItemIndex() == 0) {
if ( freq == 0 )
freq = 0.5;
txtFreq << "f = " << (freq + ((freq*2) * (fine/100)));
} else {
freq = pow(10,((int)freq)&3);
freq = freq + ((freq*10) * (fine/100));
txtFreq << freq << " Hz";
}
int det = detune->getValue() - 7;
if ( det != 0 ) {
if ( det > 0 )
txtFreq << " +" << det;
else
txtFreq << " " << det;
}
khzDisplay->setText(txtFreq, NotificationType::dontSendNotification);
envDisplay->repaint();
}
void OperatorEditor::updateEnv() {
//envDisplay->update(s_)
//envDisplay->update(s_)
}
//[/MiscUserCode]

@ -31,19 +31,20 @@ DexedAudioProcessorEditor::DexedAudioProcessorEditor (DexedAudioProcessor* owner
: AudioProcessorEditor (ownerFilter),
midiKeyboard (ownerFilter->keyboardState, MidiKeyboardComponent::horizontalKeyboard)
{
LookAndFeel::setDefaultLookAndFeel(&dx_lnf);
// This is where our plugin's editor size is set.
setSize (865, 420);
processor = ownerFilter;
cachedImage_background_png = ImageCache::getFromMemory (BinaryData::background_png, BinaryData::background_pngSize);
addAndMakeVisible (loadButton = new TextButton("LOAD"));
loadButton->setButtonText ("LOAD");
loadButton->addListener (this);
loadButton->setBounds (5, 5, 50, 18);
cachedImage_background_png = ImageCache::getFromMemory (BinaryData::background_png, BinaryData::background_pngSize);
loadButton->setBounds(5, 5, 50, 18);
addAndMakeVisible( saveButton = new TextButton("SAVE"));
saveButton->setButtonText ("SAVE");
@ -66,12 +67,7 @@ DexedAudioProcessorEditor::DexedAudioProcessorEditor (DexedAudioProcessor* owner
presets.setTextWhenNothingSelected (String::empty);
presets.setBounds(115, 5, 180, 18);
for(int i=0;i<processor->getNumPrograms();i++) {
String id;
id << (i+1) << ". " << processor->getProgramName(i);
presets.addItem(id, i+1);
}
presets.setSelectedId(processor->getCurrentProgram()+1, NotificationType::dontSendNotification);
rebuildPresetCombobox();
presets.addListener(this);
// OPERATORS
@ -130,7 +126,7 @@ void DexedAudioProcessorEditor::paint (Graphics& g) {
void DexedAudioProcessorEditor::buttonClicked(Button *buttonThatWasClicked) {
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);
if ( fc.browseForFileToOpen()) {
String f = fc.getResults().getReference(0).getFullPathName();
@ -143,14 +139,10 @@ void DexedAudioProcessorEditor::buttonClicked(Button *buttonThatWasClicked) {
return;
}
fp_in.read((char *)syx_data, 4104);
fp_in.close();
processor->importSysex((char *) &syx_data);
presets.clear(NotificationType::dontSendNotification);
for(int i=0;i<processor->getNumPrograms();i++) {
String id;
id << (i+1) << ". " << processor->getProgramName(i);
presets.addItem(id, i+1);
}
rebuildPresetCombobox();
presets.setSelectedId(processor->getCurrentProgram()+1, NotificationType::dontSendNotification);
processor->setCurrentProgram(0);
@ -160,9 +152,62 @@ void DexedAudioProcessorEditor::buttonClicked(Button *buttonThatWasClicked) {
return;
}
if (buttonThatWasClicked == saveButton) {
FileChooser fc ("Export DX sysex...", File::nonexistent, "*.syx", 1);
if ( fc.browseForFileToSave(true) ) {
String f = fc.getResults().getReference(0).getFullPathName();
uint8_t syx_data[4104];
processor->exportSysex((char *) syx_data);
ofstream fp_out(f.toRawUTF8(), ios::binary);
fp_out.write((char *)syx_data, 4104);
fp_out.close();
if (fp_out.fail()) {
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
"Error",
"Unable to write: " + f);
return;
}
}
return;
}
if (buttonThatWasClicked == storeButton) {
AlertWindow dialog(String("Store Program Destination"), "", AlertWindow::NoIcon, this);
dialog.addTextEditor(String("Name"), processor->getProgramName(processor->getCurrentProgram()), String("Name"), false);
StringArray programs;
for(int i=0;i<32;i++) {
programs.add(presets.getItemText(i));
}
dialog.addComboBox(String("Dest"), programs);
dialog.addButton("OK", 0, KeyPress(KeyPress::returnKey));
dialog.addButton("Cancel", 1, KeyPress(KeyPress::escapeKey));
if ( dialog.runModalLoop() == 0 ) {
TextEditor *name = dialog.getTextEditor(String("Name"));
ComboBox *dest = dialog.getComboBoxComponent(String("Dest"));
int programNum = dest->getSelectedItemIndex();
const char *programName = name->getText().toRawUTF8();
processor->packProgram(programNum, programName);
rebuildPresetCombobox();
processor->setCurrentProgram(programNum);
processor->updateHostDisplay();
}
return;
}
if (buttonThatWasClicked == aboutButton) {
AlertWindow::showMessageBoxAsync(AlertWindow::NoIcon, "DEXED - DX Emulator", "(c) 2013 Pascal Gauthier\nUnder the GPL v2"
"\nBased on Music Synthesizer for Android\n");
AlertWindow::showMessageBoxAsync(AlertWindow::NoIcon, "DEXED - DX Emulator 0.3", "https://github.com/asb2m10/dexed\n"
"(c) 2013 Pascal Gauthier\nUnder the GPL v2\n\n"
"Based on Music Synthesizer for Android\nhttps://code.google.com/p/music-synthesizer-for-android");
return;
}
@ -206,3 +251,14 @@ void DexedAudioProcessorEditor::updateUI() {
global.repaint();
}
void DexedAudioProcessorEditor::rebuildPresetCombobox() {
presets.clear(NotificationType::dontSendNotification);
for(int i=0;i<processor->getNumPrograms();i++) {
String id;
id << (i+1) << ". " << processor->getProgramName(i);
presets.addItem(id, i+1);
}
presets.setSelectedId(processor->getCurrentProgram()+1, NotificationType::dontSendNotification);
}

@ -60,6 +60,8 @@ public:
GlobalEditor global;
void updateUI();
void rebuildPresetCombobox();
Image cachedImage_background_png;
};

@ -10,7 +10,7 @@
==============================================================================
*/
#define _USE_MATH_DEFINES
#define _USE_MATH_DEFINES
#include <math.h>
#include "PluginFx.h"
#include "PluginProcessor.h"
@ -36,22 +36,22 @@ static float gaintable[199] = {
static inline float saturate(float input) { //clamp without branching
#define _limit 0.95
float x1 = fabsf( input + _limit );
float x2 = fabsf( input - _limit );
return 0.5 * (x1 - x2);
float x1 = fabsf( input + _limit );
float x2 = fabsf( input - _limit );
return 0.5 * (x1 - x2);
}
static inline float crossfade(float amount, float a, float b) {
return (1-amount) * a + amount * b;
return (1-amount) * a + amount * b;
}
void PluginFx::init(int sampleRate) {
uiCutoff = 1;
uiReso = 0;
srate = sampleRate;
output = 0;
for(int i=0;i<4;i++)
state[i] = 0;
output = 0;
for(int i=0;i<4;i++)
state[i] = 0;
}
void PluginFx::process(float *work, int sampleSize) {
@ -60,36 +60,36 @@ void PluginFx::process(float *work, int sampleSize) {
if ( uiCutoff == 1 )
return;
// the UI values haved changed
if ( uiCutoff != pCutoff || uiReso != pReso) {
// calc cutoff
// the UI values haved changed
if ( uiCutoff != pCutoff || uiReso != pReso) {
// calc cutoff
// mel scale freq : http://www.speech.kth.se/~giampi/auditoryscales/
float freqCutoff = 700 * (pow(M_E,(uiCutoff*4000/1127)-1)) + 20;
float fc = 2 * freqCutoff / srate;
float x2 = fc*fc;
float x3 = fc*x2;
p = -0.69346 * x3 - 0.59515 * x2 + 3.2937 * fc - 1.0072; //cubic fit
float freqCutoff = 700 * (pow(M_E,(uiCutoff*4000/1127)-1)) + 20;
float fc = 2 * freqCutoff / srate;
float x2 = fc*fc;
float x3 = fc*x2;
p = -0.69346 * x3 - 0.59515 * x2 + 3.2937 * fc - 1.0072; //cubic fit
// calc reso
float ix = p * 99;
int ixint = floor( ix );
float ixfrac = ix - ixint;
Q = uiReso * crossfade( ixfrac, gaintable[ ixint + 99 ], gaintable[ ixint + 100 ] );
// calc reso
float ix = p * 99;
int ixint = floor( ix );
float ixfrac = ix - ixint;
Q = uiReso * crossfade( ixfrac, gaintable[ ixint + 99 ], gaintable[ ixint + 100 ] );
pCutoff = uiCutoff;
pReso = uiReso;
}
pCutoff = uiCutoff;
pReso = uiReso;
}
for (int i=0; i < sampleSize; i++ ) {
output = 0.10 * ( work[i] - output ); //negative feedback
for(int pole=0; pole < 4; pole++) {
float temp = state[pole];
output = saturate( output + p * (output - temp));
state[pole] = output;
output = saturate( output + temp );
}
work[i] = output;
output *= Q; //scale the feedback
}
for (int i=0; i < sampleSize; i++ ) {
output = 0.10 * ( work[i] - output ); //negative feedback
for(int pole=0; pole < 4; pole++) {
float temp = state[pole];
output = saturate( output + p * (output - temp));
state[pole] = output;
output = saturate( output + temp );
}
work[i] = output;
output *= Q; //scale the feedback
}
}

@ -87,21 +87,21 @@ void Ctrl::comboBoxChanged(ComboBox* combo) {
// ************************************************************************
// CtrlDX - control DX mapping
CtrlFloat::CtrlFloat(String name, float *storageValue) : Ctrl(name) {
vPointer = storageValue;
vPointer = storageValue;
}
float CtrlFloat::getValueHost() {
return *vPointer;
return *vPointer;
}
void CtrlFloat::setValueHost(float v) {
*vPointer = v;
*vPointer = v;
}
String CtrlFloat::getValueDisplay() {
String display;
display << *vPointer;
return display;
String display;
display << *vPointer;
return display;
}
void CtrlFloat::updateComponent() {
@ -152,11 +152,11 @@ String CtrlDX::getValueDisplay() {
}
void CtrlDX::publishValue(float value) {
Ctrl::publishValue(value / steps);
Ctrl::publishValue(value / steps);
DexedAudioProcessorEditor *editor = (DexedAudioProcessorEditor *) parent->getActiveEditor();
DexedAudioProcessorEditor *editor = (DexedAudioProcessorEditor *) parent->getActiveEditor();
if ( editor == NULL )
return;
return;
String msg;
msg << label << " = " << getValueDisplay();
editor->global.setParamMessage(msg);
@ -352,7 +352,10 @@ void DexedAudioProcessor::initCtrl() {
}
int DexedAudioProcessor::importSysex(const char *imported) {
memcpy(sysex, imported + 6, 4104);
// reset current program
currentProgram = 0;
memcpy(sysex, imported + 6, 4096);
for (int i = 0; i < 32; i++) {
memcpy(patchNames[i], sysex + ((i * 128) + 118), 11);
@ -380,6 +383,26 @@ int DexedAudioProcessor::importSysex(const char *imported) {
return 0;
}
void DexedAudioProcessor::exportSysex(char *dest) {
uint8_t header[] = { 0xF0, 0x43, 0x00, 0x09, 0x20, 0x00 };
memcpy(dest, header, 6);
// copy 32 voices
memcpy(dest+6, sysex, 4096);
// make checksum for dump
uint8_t footer[] = { 0x00, 0xF7 };
uint8_t sum = 0;
for (int i=0; i<4096; i++)
sum = (sum + sysex[i]) % (1 << 8);
footer[0] = ((1 << 8) - sum);
memcpy(dest+4102, footer, 2);
}
/*
*/
void DexedAudioProcessor::unpackProgram(int idx) {
char *bulk = sysex + (idx * 128);
@ -416,7 +439,43 @@ void DexedAudioProcessor::unpackProgram(int idx) {
data[157] = 1;
data[158] = 1;
data[159] = 1;
data[160] = 1;
data[160] = 1;
}
void DexedAudioProcessor::packProgram(int idx, const char *name) {
char *bulk = sysex + (idx * 128);
for(int op = 0; op < 6; op++) {
// eg rate and level, brk pt, depth, scaling
memcpy(bulk + op * 17, data + op * 21, 11);
int pp = op*17;
int up = op*21;
bulk[pp+11] = (data[up+11]&0x03) | ((data[up+12]&0x03) << 2);
bulk[pp+12] = (data[up+13]&0x07) | ((data[up+20]*0x0f) << 3);
bulk[pp+13] = (data[up+14]&0x03) | ((data[up+15]*0x07) << 2);
bulk[pp+14] = data[up+16];
}
memcpy(bulk + 102, data + 126, 9); // pitch env, algo
bulk[111] = (data[135]&0x07) | ((data[136]&0x01) << 3);
memcpy(bulk + 112, data + 137, 4); // lfo
bulk[116] = (data[141]&0x01) | (((data[142]&0x07) << 1) | ((data[143]&0x07) << 4));
int eos = 0;
for(int i=0; i < 10; i++) {
char c = name[i];
if ( c == 0 )
eos = 1;
if ( eos ) {
bulk[117+i] = ' ';
continue;
}
c = c < 32 ? ' ' : c;
c = c > 127 ? ' ' : c;
bulk[117+i] = c;
}
memcpy(patchNames[idx], bulk+117, 10);
patchNames[idx][10] = 0;
}
void DexedAudioProcessor::updateProgramFromSysex(const uint8 *rawdata) {

@ -64,10 +64,6 @@ class DexedAudioProcessor : public AudioProcessor
char sysex[4096];
char patchNames[32][13];
void packProgram(int idx);
void unpackProgram(int idx);
void updateProgramFromSysex(const uint8 *rawdata);
/**
* PlugFX
*/
@ -88,7 +84,6 @@ class DexedAudioProcessor : public AudioProcessor
void initCtrl();
public :
static const int REFRESH_MSG = 1;
static const int REFRESH_COMP = 1 << 1;
@ -118,6 +113,7 @@ public :
ScopedPointer<CtrlFloat> fxReso;
int importSysex(const char *imported);
void exportSysex(char *dest);
void setDxValue(int offset, int v);
//==============================================================================
@ -134,6 +130,9 @@ public :
bool hasEditor() const;
void updateUI();
bool peekEnvStatus(int32_t *values);
void packProgram(int idx, const char *name);
void unpackProgram(int idx);
void updateProgramFromSysex(const uint8 *rawdata);
//==============================================================================
const String getName() const;

Loading…
Cancel
Save