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)
+ Amp CC messages (except for on/off)
+ Reverb CC messages
+ Delay CC messages
I'm using WinPCAP and tshark to snoop communication and plan to
implement all features accessible from the Fender FUSE application.

58
amp.cpp
View file

@ -3,13 +3,29 @@
#include "mustang.h"
int
AmpCC::control_common1( int parm, int bucket, int value ) {
return amp->control_common1( parm, bucket, value );
AmpCC::continuous_control( int parm5, int parm6, int parm7, int 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
AmpCC::control_common2( int parm, int bucket, int value ) {
return amp->control_common2( parm, bucket, value );
AmpCC::discrete_control( int parm5, int parm6, int parm7, int 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
@ -68,96 +84,96 @@ AmpCC::dispatch( int cc, int value ) {
int
AmpCC::cc69( int value ) {
return control_common1( 0x01, 0x0c, value );
return continuous_control( 0x01, 0x01, 0x0c, value );
}
int
AmpCC::cc70( int value ) {
return control_common1( 0x00, 0x0c, value );
return continuous_control( 0x00, 0x00, 0x0c, value );
}
int
AmpCC::cc71( int value ) {
return control_common1( 0x04, 0x0c, value );
return continuous_control( 0x04, 0x04, 0x0c, value );
}
int
AmpCC::cc72( int value ) {
return control_common1( 0x05, 0x0c, value );
return continuous_control( 0x05, 0x05, 0x0c, value );
}
int
AmpCC::cc73( int value ) {
return control_common1( 0x06, 0x0c, value );
return continuous_control( 0x06, 0x06, 0x0c, value );
}
int
AmpCC::cc74( int value ) {
if ( value > 2 ) return 0;
return control_common2( 0x13, 0x8f, value );
return discrete_control( 0x13, 0x13, 0x8f, value );
}
int
AmpCC::cc75( int value ) {
return control_common1( 0x0a, 0x0d, value );
return continuous_control( 0x0a, 0x0a, 0x0d, value );
}
int
AmpCC::cc76( int value ) {
if ( value > 4 ) return 0;
return control_common2( 0x0f, 0x90, value );
return discrete_control( 0x0f, 0x0f, 0x90, value );
}
int
AmpCC::cc77( int value ) {
if ( value < 1 || value > 12 ) return 0;
return control_common2( 0x11, 0x8e, value );
return discrete_control( 0x11, 0x11, 0x8e, value );
}
int
AmpCC1::cc78( int value ) {
return control_common1( 0x07, 0x0c, value );
return continuous_control( 0x07, 0x07, 0x0c, value );
}
int
AmpCC1::cc79( int value ) {
return control_common1( 0x02, 0x0c, value );
return continuous_control( 0x02, 0x02, 0x0c, value );
}
int
AmpCC2::cc78( int value ) {
return control_common1( 0x02, 0x0c, value );
return continuous_control( 0x02, 0x02, 0x0c, value );
}
int
AmpCC2::cc79( int value ) {
return control_common1( 0x03, 0x0c, value );
return continuous_control( 0x03, 0x03, 0x0c, value );
}
int
AmpCC3::cc78( int value ) {
return control_common1( 0x07, 0x0c, value );
return continuous_control( 0x07, 0x07, 0x0c, value );
}
int
AmpCC3::cc79( int value ) {
return control_common1( 0x03, 0x0c, value );
return continuous_control( 0x03, 0x03, 0x0c, value );
}
int
AmpCC4::cc78( int value ) {
return control_common1( 0x07, 0x0c, value );
return continuous_control( 0x07, 0x07, 0x0c, value );
}
int
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
// derived classes through these methods.
int control_common1( int parm, int bucket, int value );
int control_common2( int parm, int bucket, int value );
int continuous_control( int parm5, int parm6, int parm7, int value );
int discrete_control( int parm5, int parm6, int parm7, int value );
public:
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 "magic.h"
#include "amp.h"
#include "reverb.h"
#include "delay.h"
#include "amp_defaults.h"
#include "reverb_defaults.h"
#include "delay_defaults.h"
Mustang::Mustang()
{
@ -130,8 +136,9 @@ int Mustang::start_amp(void)
// Current preset name, amp settings, efx settings
for(j = 0; j < 7; i++, j++) memcpy(curr_state[j], received_data[i], LENGTH);
updateAmp();
curr_reverb = new ReverbCC( this );
updateAmpObj();
updateReverbObj();
updateDelayObj();
return 0;
}
@ -166,9 +173,9 @@ int Mustang::stop_amp()
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) {
case F57_DELUXE_ID:
case F57_CHAMP_ID:
@ -214,8 +221,62 @@ void Mustang::updateAmp(void) {
}
void Mustang::updateReverb(void) {
// No-op for now
void Mustang::updateReverbObj(void) {
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;
}
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 ret, received;
unsigned char scratch[LENGTH];
@ -372,7 +370,7 @@ int Mustang::setAmp( int ord ) {
// Copy to current setting store
memcpy(curr_state[AMP_STATE], array, LENGTH);
updateAmp();
updateAmpObj();
// Setup USB gain
memset(scratch, 0x00, LENGTH);
@ -445,7 +443,62 @@ int Mustang::setReverb( int ord ) {
// Copy to current setting store
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;
}
@ -477,34 +530,27 @@ int Mustang::save_on_amp(char *name, int slot)
return ret;
}
int Mustang::efx_common1(int parm, int bucket, int type, int value)
{
static unsigned short previous = 0;
int Mustang::continuous_control( const Mustang::Cmd & cmd ) {
int ret, received;
unsigned char array[LENGTH];
memset(array, 0x00, LENGTH);
array[0] = 0x05;
array[1] = 0xc3;
array[2] = 0x06;
array[3] = curr_state[type][EFFECT];
array[2] = cmd.parm2;
array[3] = curr_state[cmd.state_index][MODEL];
// target parameter
array[5] = array[6] = parm;
// bucket
array[7] = bucket;
array[5] = cmd.parm5;
array[6] = cmd.parm6;
array[7] = cmd.parm7;
// 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;
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;
@ -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 ret, received;
@ -536,7 +607,7 @@ int Mustang::load_memory_bank( int slot )
if(i < 7)
memcpy(curr_state[i], array, LENGTH);
}
updateAmp();
updateAmpObj();
return ret;
}

View file

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

View file

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

View file

@ -3,8 +3,16 @@
#include "mustang.h"
int
ReverbCC::efx_common1(int parm, int bucket, int type, int value) {
return amp->efx_common1( parm, bucket, type, value );
ReverbCC::continuous_control( int parm5, int parm6, int parm7, int 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
@ -39,26 +47,26 @@ ReverbCC::dispatch( int cc, int value ) {
int
ReverbCC::cc59( int value ) {
return efx_common1( 0x00, 0x0b, REVERB_STATE, value );
return continuous_control( 0x00, 0x00, 0x0b, value );
}
int
ReverbCC::cc60( int value ) {
return efx_common1( 0x01, 0x0b, REVERB_STATE, value );
return continuous_control( 0x01, 0x01, 0x0b, value );
}
int
ReverbCC::cc61( int value ) {
return efx_common1( 0x02, 0x0b, REVERB_STATE, value );
return continuous_control( 0x02, 0x02, 0x0b, value );
}
int
ReverbCC::cc62( int value ) {
return efx_common1( 0x03, 0x0b, REVERB_STATE, value );
return continuous_control( 0x03, 0x03, 0x0b, value );
}
int
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:
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:
ReverbCC( Mustang * theAmp ) : amp(theAmp) {}