Implement Delay CC

This commit is contained in:
hirsch 2016-06-26 18:13:02 -04:00
parent 1130fceea5
commit 6638fc5bf3
11 changed files with 720 additions and 140 deletions

View file

@ -27,6 +27,7 @@ implemented:
+ EFX bypass (on/off) + EFX bypass (on/off)
+ Amp CC messages (except for on/off) + Amp CC messages (except for on/off)
+ Reverb CC messages + Reverb CC messages
+ Delay CC messages
I'm using WinPCAP and tshark to snoop communication and plan to I'm using WinPCAP and tshark to snoop communication and plan to
implement all features accessible from the Fender FUSE application. implement all features accessible from the Fender FUSE application.

58
amp.cpp
View file

@ -3,13 +3,29 @@
#include "mustang.h" #include "mustang.h"
int int
AmpCC::control_common1( int parm, int bucket, int value ) { AmpCC::continuous_control( int parm5, int parm6, int parm7, int value ) {
return amp->control_common1( parm, bucket, value ); Mustang::Cmd cmd;
cmd.state_index = AMP_STATE;
cmd.parm2 = 0x02;
cmd.parm5 = parm5;
cmd.parm6 = parm6;
cmd.parm7 = parm7;
cmd.value = value;
return amp->continuous_control( cmd );
} }
int int
AmpCC::control_common2( int parm, int bucket, int value ) { AmpCC::discrete_control( int parm5, int parm6, int parm7, int value ) {
return amp->control_common2( parm, bucket, value ); Mustang::Cmd cmd;
cmd.state_index = AMP_STATE;
cmd.parm2 = 0x02;
cmd.parm5 = parm5;
cmd.parm6 = parm6;
cmd.parm7 = parm7;
cmd.value = value;
return amp->discrete_control( cmd );
} }
int int
@ -68,96 +84,96 @@ AmpCC::dispatch( int cc, int value ) {
int int
AmpCC::cc69( int value ) { AmpCC::cc69( int value ) {
return control_common1( 0x01, 0x0c, value ); return continuous_control( 0x01, 0x01, 0x0c, value );
} }
int int
AmpCC::cc70( int value ) { AmpCC::cc70( int value ) {
return control_common1( 0x00, 0x0c, value ); return continuous_control( 0x00, 0x00, 0x0c, value );
} }
int int
AmpCC::cc71( int value ) { AmpCC::cc71( int value ) {
return control_common1( 0x04, 0x0c, value ); return continuous_control( 0x04, 0x04, 0x0c, value );
} }
int int
AmpCC::cc72( int value ) { AmpCC::cc72( int value ) {
return control_common1( 0x05, 0x0c, value ); return continuous_control( 0x05, 0x05, 0x0c, value );
} }
int int
AmpCC::cc73( int value ) { AmpCC::cc73( int value ) {
return control_common1( 0x06, 0x0c, value ); return continuous_control( 0x06, 0x06, 0x0c, value );
} }
int int
AmpCC::cc74( int value ) { AmpCC::cc74( int value ) {
if ( value > 2 ) return 0; if ( value > 2 ) return 0;
return control_common2( 0x13, 0x8f, value ); return discrete_control( 0x13, 0x13, 0x8f, value );
} }
int int
AmpCC::cc75( int value ) { AmpCC::cc75( int value ) {
return control_common1( 0x0a, 0x0d, value ); return continuous_control( 0x0a, 0x0a, 0x0d, value );
} }
int int
AmpCC::cc76( int value ) { AmpCC::cc76( int value ) {
if ( value > 4 ) return 0; if ( value > 4 ) return 0;
return control_common2( 0x0f, 0x90, value ); return discrete_control( 0x0f, 0x0f, 0x90, value );
} }
int int
AmpCC::cc77( int value ) { AmpCC::cc77( int value ) {
if ( value < 1 || value > 12 ) return 0; if ( value < 1 || value > 12 ) return 0;
return control_common2( 0x11, 0x8e, value ); return discrete_control( 0x11, 0x11, 0x8e, value );
} }
int int
AmpCC1::cc78( int value ) { AmpCC1::cc78( int value ) {
return control_common1( 0x07, 0x0c, value ); return continuous_control( 0x07, 0x07, 0x0c, value );
} }
int int
AmpCC1::cc79( int value ) { AmpCC1::cc79( int value ) {
return control_common1( 0x02, 0x0c, value ); return continuous_control( 0x02, 0x02, 0x0c, value );
} }
int int
AmpCC2::cc78( int value ) { AmpCC2::cc78( int value ) {
return control_common1( 0x02, 0x0c, value ); return continuous_control( 0x02, 0x02, 0x0c, value );
} }
int int
AmpCC2::cc79( int value ) { AmpCC2::cc79( int value ) {
return control_common1( 0x03, 0x0c, value ); return continuous_control( 0x03, 0x03, 0x0c, value );
} }
int int
AmpCC3::cc78( int value ) { AmpCC3::cc78( int value ) {
return control_common1( 0x07, 0x0c, value ); return continuous_control( 0x07, 0x07, 0x0c, value );
} }
int int
AmpCC3::cc79( int value ) { AmpCC3::cc79( int value ) {
return control_common1( 0x03, 0x0c, value ); return continuous_control( 0x03, 0x03, 0x0c, value );
} }
int int
AmpCC4::cc78( int value ) { AmpCC4::cc78( int value ) {
return control_common1( 0x07, 0x0c, value ); return continuous_control( 0x07, 0x07, 0x0c, value );
} }
int int
AmpCC4::cc79( int value ) { AmpCC4::cc79( int value ) {
return control_common1( 0x03, 0x0c, value ); return continuous_control( 0x03, 0x03, 0x0c, value );
} }

4
amp.h
View file

@ -18,8 +18,8 @@ protected:
// Only base class is friend of Mustang, so forward calls from // Only base class is friend of Mustang, so forward calls from
// derived classes through these methods. // derived classes through these methods.
int control_common1( int parm, int bucket, int value ); int continuous_control( int parm5, int parm6, int parm7, int value );
int control_common2( int parm, int bucket, int value ); int discrete_control( int parm5, int parm6, int parm7, int value );
public: public:
AmpCC( Mustang * theAmp ) : amp(theAmp) {} AmpCC( Mustang * theAmp ) : amp(theAmp) {}

229
delay.cpp Normal file
View file

@ -0,0 +1,229 @@
#include "delay.h"
#include "mustang.h"
int
DelayCC::continuous_control( int parm5, int parm6, int parm7, int value ) {
Mustang::Cmd cmd;
cmd.state_index = DELAY_STATE;
cmd.parm2 = 0x05;
cmd.parm5 = parm5;
cmd.parm6 = parm6;
cmd.parm7 = parm7;
cmd.value = value;
return amp->continuous_control( cmd );
}
int
DelayCC::discrete_control( int parm5, int parm6, int parm7, int value ) {
Mustang::Cmd cmd;
cmd.state_index = DELAY_STATE;
cmd.parm2 = 0x05;
cmd.parm5 = parm5;
cmd.parm6 = parm6;
cmd.parm7 = parm7;
cmd.value = value;
return amp->discrete_control( cmd );
}
int
DelayCC::dispatch( int cc, int value ) {
switch ( cc ) {
case 49:
// Level
return cc49( value );
break;
case 50:
// Delay Time
return cc50( value );
break;
case 51:
// Feedback / FFdbk
return cc51( value );
break;
case 52:
// Brightness / Frequency / Release / RFdbk / Flutter
return cc52( value );
break;
case 53:
// Attenuation / Resonance / Mode / Stereo / Threshold
// Tone / Brightness / Separation
return cc53( value );
break;
case 54:
// Input Level / Stereo / Brightness
return cc54( value );
break;
default:
return 0;
break;
}
}
int
DelayCC::cc49( int value ) {
return continuous_control( 0x00, 0x00, 0x01, value );
}
int
DelayCC::cc50( int value ) {
return continuous_control( 0x01, 0x01, 0x06, value );
}
int
MonoDelayCC::cc51( int value ) {
return continuous_control( 0x02, 0x02, 0x01, value );
}
int
MonoDelayCC::cc52( int value ) {
return continuous_control( 0x03, 0x03, 0x01, value );
}
int
MonoDelayCC::cc53( int value ) {
return continuous_control( 0x04, 0x04, 0x01, value );
}
int
EchoFilterCC::cc51( int value ) {
return continuous_control( 0x02, 0x02, 0x01, value );
}
int
EchoFilterCC::cc52( int value ) {
return continuous_control( 0x03, 0x03, 0x01, value );
}
int
EchoFilterCC::cc53( int value ) {
return continuous_control( 0x04, 0x04, 0x01, value );
}
int
EchoFilterCC::cc54( int value ) {
return continuous_control( 0x05, 0x05, 0x01, value );
}
int
MultitapDelayCC::cc51( int value ) {
return continuous_control( 0x02, 0x02, 0x01, value );
}
int
MultitapDelayCC::cc52( int value ) {
return continuous_control( 0x03, 0x03, 0x01, value );
}
int
MultitapDelayCC::cc53( int value ) {
if ( value > 3 ) return 0;
return discrete_control( 0x04, 0x04, 0x8b, value );
}
int
PingPongDelayCC::cc51( int value ) {
return continuous_control( 0x02, 0x02, 0x01, value );
}
int
PingPongDelayCC::cc52( int value ) {
return continuous_control( 0x03, 0x03, 0x01, value );
}
int
PingPongDelayCC::cc53( int value ) {
return continuous_control( 0x04, 0x04, 0x01, value );
}
int
DuckingDelayCC::cc51( int value ) {
return continuous_control( 0x02, 0x02, 0x01, value );
}
int
DuckingDelayCC::cc52( int value ) {
return continuous_control( 0x03, 0x03, 0x01, value );
}
int
DuckingDelayCC::cc53( int value ) {
return continuous_control( 0x04, 0x04, 0x01, value );
}
int
ReverseDelayCC::cc51( int value ) {
return continuous_control( 0x02, 0x02, 0x01, value );
}
int
ReverseDelayCC::cc52( int value ) {
return continuous_control( 0x03, 0x03, 0x01, value );
}
int
ReverseDelayCC::cc53( int value ) {
return continuous_control( 0x04, 0x04, 0x01, value );
}
int
TapeDelayCC::cc51( int value ) {
return continuous_control( 0x02, 0x02, 0x01, value );
}
int
TapeDelayCC::cc52( int value ) {
return continuous_control( 0x03, 0x03, 0x01, value );
}
int
TapeDelayCC::cc53( int value ) {
return continuous_control( 0x04, 0x04, 0x01, value );
}
int
TapeDelayCC::cc54( int value ) {
return continuous_control( 0x05, 0x05, 0x01, value );
}
int
StereoTapeDelayCC::cc51( int value ) {
return continuous_control( 0x02, 0x02, 0x01, value );
}
int
StereoTapeDelayCC::cc52( int value ) {
return continuous_control( 0x03, 0x03, 0x01, value );
}
int
StereoTapeDelayCC::cc53( int value ) {
return continuous_control( 0x04, 0x05, 0x01, value );
}
int
StereoTapeDelayCC::cc54( int value ) {
return continuous_control( 0x05, 0x04, 0x01, value );
}

144
delay.h Normal file
View file

@ -0,0 +1,144 @@
// -*-c++-*-
#ifndef _DELAY_H
#define _DELAY_H
class Mustang;
class DelayCC {
protected:
Mustang * amp;
int continuous_control( int parm5, int parm6, int parm7, int value );
int discrete_control( int parm5, int parm6, int parm7, int value );
public:
DelayCC( Mustang * theAmp ) : amp(theAmp) {}
int dispatch( int cc, int value );
private:
// Level
virtual int cc49( int value );
// Delay Time
virtual int cc50( int value );
virtual int cc51( int value ) { return 0;}
virtual int cc52( int value ) { return 0;}
virtual int cc53( int value ) { return 0;}
virtual int cc54( int value ) { return 0;}
};
class MonoDelayCC : public DelayCC {
public:
MonoDelayCC( Mustang * theAmp ) : DelayCC(theAmp) {}
private:
// Feedback
virtual int cc51( int value );
// Brightness
virtual int cc52( int value );
// Attenuation
virtual int cc53( int value );
};
class EchoFilterCC : public DelayCC {
public:
EchoFilterCC( Mustang * theAmp ) : DelayCC(theAmp) {}
private:
// Feedback
virtual int cc51( int value );
// Frequency
virtual int cc52( int value );
// Resonance
virtual int cc53( int value );
// Input Level
virtual int cc54( int value );
};
class MultitapDelayCC : public DelayCC {
public:
MultitapDelayCC( Mustang * theAmp ) : DelayCC(theAmp) {}
private:
// Feedback
virtual int cc51( int value );
// Brightness
virtual int cc52( int value );
// Mode
virtual int cc53( int value );
};
class PingPongDelayCC : public DelayCC {
public:
PingPongDelayCC( Mustang * theAmp ) : DelayCC(theAmp) {}
private:
// Feedback
virtual int cc51( int value );
// Brightness
virtual int cc52( int value );
// Stereo
virtual int cc53( int value );
};
class DuckingDelayCC : public DelayCC {
public:
DuckingDelayCC( Mustang * theAmp ) : DelayCC(theAmp) {}
private:
// Feedback
virtual int cc51( int value );
// Release
virtual int cc52( int value );
// Threshold
virtual int cc53( int value );
};
class ReverseDelayCC : public DelayCC {
public:
ReverseDelayCC( Mustang * theAmp ) : DelayCC(theAmp) {}
private:
// FFdbk
virtual int cc51( int value );
// RFdbk
virtual int cc52( int value );
// Tone
virtual int cc53( int value );
};
class TapeDelayCC : public DelayCC {
public:
TapeDelayCC( Mustang * theAmp ) : DelayCC(theAmp) {}
private:
// Feedback
virtual int cc51( int value );
// Flutter
virtual int cc52( int value );
// Brightness
virtual int cc53( int value );
// Stereo
virtual int cc54( int value );
};
class StereoTapeDelayCC : public DelayCC {
public:
StereoTapeDelayCC( Mustang * theAmp ) : DelayCC(theAmp) {}
private:
// Feedback
virtual int cc51( int value );
// Flutter
virtual int cc52( int value );
// Separation
virtual int cc53( int value );
// Brightness
virtual int cc54( int value );
};
#endif

67
delay_defaults.h Normal file
View file

@ -0,0 +1,67 @@
// Default settings for Mustang III (original) delay models
//
// This header is auto-generated from decoded pcap capture.
static unsigned char mono_delay[] = {
0x1c, 0x03, 0x08, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x16, 0x00, 0x06, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static unsigned char mono_echo_filter[] = {
0x1c, 0x03, 0x08, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x43, 0x00, 0x06, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static unsigned char stereo_echo_filter[] = {
0x1c, 0x03, 0x08, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x48, 0x00, 0x06, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0xb3, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static unsigned char multitap_delay[] = {
0x1c, 0x03, 0x08, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x44, 0x00, 0x06, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x80, 0x66, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static unsigned char ping_pong_delay[] = {
0x1c, 0x03, 0x08, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x45, 0x00, 0x06, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static unsigned char ducking_delay[] = {
0x1c, 0x03, 0x08, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x15, 0x00, 0x06, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static unsigned char reverse_delay[] = {
0x1c, 0x03, 0x08, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x46, 0x00, 0x06, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static unsigned char tape_delay[] = {
0x1c, 0x03, 0x08, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x2b, 0x00, 0x06, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7d, 0x1c, 0x00, 0x63, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static unsigned char stereo_tape_delay[] = {
0x1c, 0x03, 0x08, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x2a, 0x00, 0x06, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7d, 0x88, 0x1c, 0x63, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

View file

@ -3,8 +3,14 @@
#include <cmath> #include <cmath>
#include "magic.h" #include "magic.h"
#include "amp.h"
#include "reverb.h"
#include "delay.h"
#include "amp_defaults.h" #include "amp_defaults.h"
#include "reverb_defaults.h" #include "reverb_defaults.h"
#include "delay_defaults.h"
Mustang::Mustang() Mustang::Mustang()
{ {
@ -130,8 +136,9 @@ int Mustang::start_amp(void)
// Current preset name, amp settings, efx settings // Current preset name, amp settings, efx settings
for(j = 0; j < 7; i++, j++) memcpy(curr_state[j], received_data[i], LENGTH); for(j = 0; j < 7; i++, j++) memcpy(curr_state[j], received_data[i], LENGTH);
updateAmp(); updateAmpObj();
curr_reverb = new ReverbCC( this ); updateReverbObj();
updateDelayObj();
return 0; return 0;
} }
@ -166,9 +173,9 @@ int Mustang::stop_amp()
return 0; return 0;
} }
void Mustang::updateAmp(void) { void Mustang::updateAmpObj(void) {
int curr = curr_state[AMP_STATE][AMPLIFIER]; int curr = curr_state[AMP_STATE][MODEL];
switch (curr) { switch (curr) {
case F57_DELUXE_ID: case F57_DELUXE_ID:
case F57_CHAMP_ID: case F57_CHAMP_ID:
@ -214,8 +221,62 @@ void Mustang::updateAmp(void) {
} }
void Mustang::updateReverb(void) { void Mustang::updateReverbObj(void) {
// No-op for now delete curr_reverb;
curr_reverb = new ReverbCC( this );
}
void Mustang::updateDelayObj(void) {
int curr = curr_state[DELAY_STATE][MODEL];
switch (curr) {
case MONO_DLY_ID:
delete curr_delay;
curr_delay = new MonoDelayCC(this);
break;
case MONO_FILTER_ID:
case ST_FILTER_ID:
delete curr_delay;
curr_delay = new EchoFilterCC(this);
break;
case MTAP_DLY_ID:
delete curr_delay;
curr_delay = new MultitapDelayCC(this);
break;
case PONG_DLY_ID:
delete curr_delay;
curr_delay = new PingPongDelayCC(this);
break;
case DUCK_DLY_ID:
delete curr_delay;
curr_delay = new DuckingDelayCC(this);
break;
case REVERSE_DLY_ID:
delete curr_delay;
curr_delay = new ReverseDelayCC(this);
break;
case TAPE_DLY_ID:
delete curr_delay;
curr_delay = new TapeDelayCC(this);
break;
case ST_TAPE_DLY_ID:
delete curr_delay;
curr_delay = new StereoTapeDelayCC(this);
break;
default:
fprintf( stderr, "W - Delay id %x not supported yet\n", curr );
break;
}
} }
@ -252,69 +313,6 @@ int Mustang::effect_toggle(int cc, int value)
return ret; return ret;
} }
int Mustang::control_common1(int parm, int bucket, int value)
{
static unsigned short previous = 0;
int ret, received;
unsigned char array[LENGTH];
memset(array, 0x00, LENGTH);
array[0] = 0x05;
array[1] = 0xc3;
array[2] = 0x02;
array[3] = curr_state[AMP_STATE][AMPLIFIER];
// target parameter
array[5] = array[6] = parm;
// bucket
array[7] = bucket;
// Scale and clamp to valid index range
int index = (int) ceil( (double)value * magic_scale_factor );
if ( index > magic_max ) index = magic_max;
unsigned short eff_value = magic_values[index];
// Try to prevent extra traffic if successive calls resolve to the same
// slot.
if (eff_value == previous) return 0;
previous = eff_value;
array[9] = eff_value & 0xff;
array[10] = (eff_value >> 8) & 0xff;
// Send command and flush reply
ret = libusb_interrupt_transfer(amp_hand, 0x01, array, LENGTH, &received, TMOUT);
libusb_interrupt_transfer(amp_hand, 0x81, array, LENGTH, &received, TMOUT);
return ret;
}
int Mustang::control_common2(int parm, int bucket, int value)
{
int ret, received;
unsigned char array[LENGTH];
memset(array, 0x00, LENGTH);
array[0] = 0x05;
array[1] = 0xc3;
array[2] = 0x02;
array[3] = curr_state[AMP_STATE][AMPLIFIER];
// target parameter
array[5] = array[6] = parm;
// bucket
array[7] = bucket;
// value
array[9] = value;
// Send command and flush reply
ret = libusb_interrupt_transfer(amp_hand, 0x01, array, LENGTH, &received, TMOUT);
libusb_interrupt_transfer(amp_hand, 0x81, array, LENGTH, &received, TMOUT);
return ret;
}
int Mustang::setAmp( int ord ) { int Mustang::setAmp( int ord ) {
int ret, received; int ret, received;
unsigned char scratch[LENGTH]; unsigned char scratch[LENGTH];
@ -372,7 +370,7 @@ int Mustang::setAmp( int ord ) {
// Copy to current setting store // Copy to current setting store
memcpy(curr_state[AMP_STATE], array, LENGTH); memcpy(curr_state[AMP_STATE], array, LENGTH);
updateAmp(); updateAmpObj();
// Setup USB gain // Setup USB gain
memset(scratch, 0x00, LENGTH); memset(scratch, 0x00, LENGTH);
@ -445,7 +443,62 @@ int Mustang::setReverb( int ord ) {
// Copy to current setting store // Copy to current setting store
memcpy(curr_state[REVERB_STATE], array, LENGTH); memcpy(curr_state[REVERB_STATE], array, LENGTH);
updateReverb(); updateReverbObj();
return ret;
}
int Mustang::setDelay( int ord ) {
int ret, received;
unsigned char scratch[LENGTH];
unsigned char *array;
switch (ord) {
case 1:
array = mono_delay;
break;
case 2:
array = mono_echo_filter;
break;
case 3:
array = stereo_echo_filter;
break;
case 4:
array = multitap_delay;
break;
case 5:
array = ping_pong_delay;
break;
case 6:
array = ducking_delay;
break;
case 7:
array = reverse_delay;
break;
case 8:
array = tape_delay;
break;
case 9:
array = stereo_tape_delay;
break;
default:
fprintf( stderr, "W - Delay select %d not supported\n", ord );
return 0;
}
array[FXSLOT] = curr_state[DELAY_STATE][FXSLOT];
// Setup amp personality
ret = libusb_interrupt_transfer(amp_hand, 0x01, array, LENGTH, &received, TMOUT);
libusb_interrupt_transfer(amp_hand, 0x81, scratch, LENGTH, &received, TMOUT);
ret = libusb_interrupt_transfer(amp_hand, 0x01, execute, LENGTH, &received, TMOUT);
libusb_interrupt_transfer(amp_hand, 0x81, scratch, LENGTH, &received, TMOUT);
// Copy to current setting store
memcpy(curr_state[DELAY_STATE], array, LENGTH);
updateDelayObj();
return ret; return ret;
} }
@ -477,34 +530,27 @@ int Mustang::save_on_amp(char *name, int slot)
return ret; return ret;
} }
int Mustang::efx_common1(int parm, int bucket, int type, int value) int Mustang::continuous_control( const Mustang::Cmd & cmd ) {
{
static unsigned short previous = 0;
int ret, received; int ret, received;
unsigned char array[LENGTH]; unsigned char array[LENGTH];
memset(array, 0x00, LENGTH); memset(array, 0x00, LENGTH);
array[0] = 0x05; array[0] = 0x05;
array[1] = 0xc3; array[1] = 0xc3;
array[2] = 0x06; array[2] = cmd.parm2;
array[3] = curr_state[type][EFFECT]; array[3] = curr_state[cmd.state_index][MODEL];
// target parameter // target parameter
array[5] = array[6] = parm; array[5] = cmd.parm5;
// bucket array[6] = cmd.parm6;
array[7] = bucket; array[7] = cmd.parm7;
// Scale and clamp to valid index range // Scale and clamp to valid index range
int index = (int) ceil( (double)value * magic_scale_factor ); int index = (int) ceil( (double)cmd.value * magic_scale_factor );
if ( index > magic_max ) index = magic_max; if ( index > magic_max ) index = magic_max;
unsigned short eff_value = magic_values[index]; unsigned short eff_value = magic_values[index];
// Try to prevent extra traffic if successive calls resolve to the same
// slot.
if (eff_value == previous) return 0;
previous = eff_value;
array[9] = eff_value & 0xff; array[9] = eff_value & 0xff;
array[10] = (eff_value >> 8) & 0xff; array[10] = (eff_value >> 8) & 0xff;
@ -516,6 +562,31 @@ int Mustang::efx_common1(int parm, int bucket, int type, int value)
} }
int Mustang::discrete_control( const Mustang::Cmd & cmd ) {
int ret, received;
unsigned char array[LENGTH];
memset(array, 0x00, LENGTH);
array[0] = 0x05;
array[1] = 0xc3;
array[2] = cmd.parm2;
array[3] = curr_state[cmd.state_index][MODEL];
array[5] = cmd.parm5;
array[6] = cmd.parm6;
array[7] = cmd.parm7;
// Discrete value
array[9] = cmd.value;
// Send command and flush reply
ret = libusb_interrupt_transfer(amp_hand, 0x01, array, LENGTH, &received, TMOUT);
libusb_interrupt_transfer(amp_hand, 0x81, array, LENGTH, &received, TMOUT);
return ret;
}
int Mustang::load_memory_bank( int slot ) int Mustang::load_memory_bank( int slot )
{ {
int ret, received; int ret, received;
@ -536,7 +607,7 @@ int Mustang::load_memory_bank( int slot )
if(i < 7) if(i < 7)
memcpy(curr_state[i], array, LENGTH); memcpy(curr_state[i], array, LENGTH);
} }
updateAmp(); updateAmpObj();
return ret; return ret;
} }

View file

@ -9,8 +9,6 @@
#include <libusb-1.0/libusb.h> #include <libusb-1.0/libusb.h>
#include "effects_enum.h" #include "effects_enum.h"
#include "data_structs.h" #include "data_structs.h"
#include "amp.h"
#include "reverb.h"
// amp's VID and PID // amp's VID and PID
#define USB_VID 0x1ed8 #define USB_VID 0x1ed8
@ -74,6 +72,9 @@
#define FAMILY 2 #define FAMILY 2
#define ACTIVE_INVERT 3 #define ACTIVE_INVERT 3
// Offset to current device model for any state structure
#define MODEL 16
// Index into current state structure // Index into current state structure
#define PRESET_NAME 0 #define PRESET_NAME 0
#define AMP_STATE 1 #define AMP_STATE 1
@ -96,7 +97,7 @@
#define DELAY_FAM 5 #define DELAY_FAM 5
#define REVERB_FAM 6 #define REVERB_FAM 6
// Amp id values // Amp model id values
#define F57_DELUXE_ID 0x67 #define F57_DELUXE_ID 0x67
#define F59_BASSMAN_ID 0x64 #define F59_BASSMAN_ID 0x64
#define F57_CHAMP_ID 0x7c #define F57_CHAMP_ID 0x7c
@ -116,7 +117,7 @@
#define BRIT_WATT_ID 0xff #define BRIT_WATT_ID 0xff
#define BRIT_COLOR_ID 0xfc #define BRIT_COLOR_ID 0xfc
// Reverb id values // Reverb model id values
#define SM_HALL_ID 0x24 #define SM_HALL_ID 0x24
#define LG_HALL_ID 0x3a #define LG_HALL_ID 0x3a
#define SM_ROOM_ID 0x26 #define SM_ROOM_ID 0x26
@ -128,9 +129,27 @@
#define SPRING_63_ID 0x21 #define SPRING_63_ID 0x21
#define SPRING_65_ID 0x0b #define SPRING_65_ID 0x0b
// Delay model id values
#define MONO_DLY_ID 0x16
#define MONO_FILTER_ID 0x43
#define ST_FILTER_ID 0x48
#define MTAP_DLY_ID 0x44
#define PONG_DLY_ID 0x45
#define DUCK_DLY_ID 0x15
#define REVERSE_DLY_ID 0x46
#define TAPE_DLY_ID 0x2b
#define ST_TAPE_DLY_ID 0x2a
class AmpCC;
class ReverbCC;
class DelayCC;
class Mustang { class Mustang {
friend class AmpCC; friend class AmpCC;
friend class ReverbCC; friend class ReverbCC;
friend class DelayCC;
public: public:
Mustang(); Mustang();
@ -138,9 +157,10 @@ public:
int start_amp(void); // initialize communication int start_amp(void); // initialize communication
int stop_amp(void); // terminate communication int stop_amp(void); // terminate communication
int set_effect(struct fx_pedal_settings); int set_effect(struct fx_pedal_settings);
int setAmp( int ord );
int setAmp( int ord );
int setReverb( int ord ); int setReverb( int ord );
int setDelay( int ord );
int save_on_amp(char *, int); int save_on_amp(char *, int);
int load_memory_bank(int); int load_memory_bank(int);
@ -150,8 +170,18 @@ public:
AmpCC * getAmp( void ) { return curr_amp;} AmpCC * getAmp( void ) { return curr_amp;}
ReverbCC * getReverb( void ) { return curr_reverb;} ReverbCC * getReverb( void ) { return curr_reverb;}
DelayCC * getDelay( void ) { return curr_delay;}
private: struct Cmd {
int state_index;
int parm2;
int parm5;
int parm6;
int parm7;
int value;
};
private:
libusb_device_handle *amp_hand; // handle for USB communication libusb_device_handle *amp_hand; // handle for USB communication
unsigned char execute[LENGTH]; // "apply" command sent after each instruction unsigned char execute[LENGTH]; // "apply" command sent after each instruction
@ -180,14 +210,14 @@ public:
AmpCC * curr_amp; AmpCC * curr_amp;
ReverbCC * curr_reverb; ReverbCC * curr_reverb;
DelayCC * curr_delay;
int control_common1(int parm, int bucket, int value); int continuous_control( const Mustang::Cmd & cmd );
int control_common2(int parm, int bucket, int value); int discrete_control( const Mustang::Cmd & cmd );
int efx_common1(int parm, int bucket, int type, int value); void updateAmpObj(void);
void updateReverbObj(void);
void updateAmp(void); void updateDelayObj(void);
void updateReverb(void);
}; };
#endif // MUSTANG_H #endif // MUSTANG_H

View file

@ -5,6 +5,11 @@
#include "mustang.h" #include "mustang.h"
#include "amp.h"
#include "reverb.h"
#include "delay.h"
static Mustang mustang; static Mustang mustang;
static int channel; static int channel;
@ -47,14 +52,23 @@ void message_action( double deltatime, std::vector< unsigned char > *message, vo
if ( cc >= 23 && cc <= 26 ) { if ( cc >= 23 && cc <= 26 ) {
rc = mustang.effect_toggle( cc, value ); rc = mustang.effect_toggle( cc, value );
} }
// Set delay model
else if ( cc == 48 ) {
rc = mustang.setDelay( value );
}
// Delay CC handler
else if ( cc >= 49 && cc <= 54 ) {
DelayCC *delayObj = mustang.getDelay();
rc = delayObj->dispatch( cc, value );
}
// Set reverb model // Set reverb model
else if ( cc == 58 ) { else if ( cc == 58 ) {
rc = mustang.setReverb( value ); rc = mustang.setReverb( value );
} }
// Reverb CC handler // Reverb CC handler
else if ( cc >= 59 && cc <= 63 ) { else if ( cc >= 59 && cc <= 63 ) {
ReverbCC *reverbModel = mustang.getReverb(); ReverbCC *reverbObj = mustang.getReverb();
rc = reverbModel->dispatch( cc, value ); rc = reverbObj->dispatch( cc, value );
} }
// Set amp model // Set amp model
else if ( cc == 68 ) { else if ( cc == 68 ) {
@ -62,8 +76,8 @@ void message_action( double deltatime, std::vector< unsigned char > *message, vo
} }
// Amp CC Handler // Amp CC Handler
else if ( cc >= 69 && cc <= 79 ) { else if ( cc >= 69 && cc <= 79 ) {
AmpCC *ampModel = mustang.getAmp(); AmpCC *ampObj = mustang.getAmp();
rc = ampModel->dispatch( cc, value ); rc = ampObj->dispatch( cc, value );
} }
if ( rc ) { if ( rc ) {
fprintf( stderr, "Error: CC#%d failed. RC = %d\n", cc, rc ); fprintf( stderr, "Error: CC#%d failed. RC = %d\n", cc, rc );

View file

@ -3,8 +3,16 @@
#include "mustang.h" #include "mustang.h"
int int
ReverbCC::efx_common1(int parm, int bucket, int type, int value) { ReverbCC::continuous_control( int parm5, int parm6, int parm7, int value ) {
return amp->efx_common1( parm, bucket, type, value ); Mustang::Cmd cmd;
cmd.state_index = REVERB_STATE;
cmd.parm2 = 0x06;
cmd.parm5 = parm5;
cmd.parm6 = parm6;
cmd.parm7 = parm7;
cmd.value = value;
return amp->continuous_control( cmd );
} }
int int
@ -39,26 +47,26 @@ ReverbCC::dispatch( int cc, int value ) {
int int
ReverbCC::cc59( int value ) { ReverbCC::cc59( int value ) {
return efx_common1( 0x00, 0x0b, REVERB_STATE, value ); return continuous_control( 0x00, 0x00, 0x0b, value );
} }
int int
ReverbCC::cc60( int value ) { ReverbCC::cc60( int value ) {
return efx_common1( 0x01, 0x0b, REVERB_STATE, value ); return continuous_control( 0x01, 0x01, 0x0b, value );
} }
int int
ReverbCC::cc61( int value ) { ReverbCC::cc61( int value ) {
return efx_common1( 0x02, 0x0b, REVERB_STATE, value ); return continuous_control( 0x02, 0x02, 0x0b, value );
} }
int int
ReverbCC::cc62( int value ) { ReverbCC::cc62( int value ) {
return efx_common1( 0x03, 0x0b, REVERB_STATE, value ); return continuous_control( 0x03, 0x03, 0x0b, value );
} }
int int
ReverbCC::cc63( int value ) { ReverbCC::cc63( int value ) {
return efx_common1( 0x04, 0x0b, REVERB_STATE, value ); return continuous_control( 0x04, 0x04, 0x0b, value );
} }

View file

@ -10,7 +10,7 @@ class ReverbCC {
protected: protected:
Mustang * amp; Mustang * amp;
int efx_common1(int parm, int bucket, int type, int value); int continuous_control( int parm5, int parm6, int parm7, int value );
public: public:
ReverbCC( Mustang * theAmp ) : amp(theAmp) {} ReverbCC( Mustang * theAmp ) : amp(theAmp) {}