diff --git a/Makefile b/Makefile index 797ad95..5e50887 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ DEP = $(subst .cpp,.d,$(SRC)) # The -M* switches automatically generate .d dependency files CPPFLAGS += -MP -MMD $(INCDIRS) -LDLIBS = -lrtmidi -lusb-1.0 +LDLIBS = -lrtmidi -lusb-1.0 -lpthread BIN = mustang_midi diff --git a/amp.cpp b/amp.cpp index 3810a7b..b51927b 100644 --- a/amp.cpp +++ b/amp.cpp @@ -1,6 +1,7 @@ #include "amp.h" #include "mustang.h" +#include "constants.h" int AmpCC::continuous_control( int parm5, int parm6, int parm7, int value ) { diff --git a/amp.h b/amp.h index 770c33e..cfecdb4 100644 --- a/amp.h +++ b/amp.h @@ -3,6 +3,8 @@ #ifndef _AMPCC_H #define _AMPCC_H +#include + class Mustang; // F57 Deluxe @@ -16,6 +18,8 @@ class AmpCC { protected: Mustang * amp; + unsigned char model[2]; + unsigned char slot; // Only base class is friend of Mustang, so forward calls from // derived classes through these methods. @@ -23,9 +27,16 @@ protected: int discrete_control( int parm5, int parm6, int parm7, int value ); public: - AmpCC( Mustang * theAmp ) : amp(theAmp) {} + AmpCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : + amp(theAmp), + slot(theSlot) + { + memcpy( this->model, model, 2 ); + } - virtual int dispatch( int cc, int value ); + int dispatch( int cc, int value ); + const unsigned char *getModel( void ) { return model;} + const unsigned char getSlot( void ) { return slot;} private: // Gain @@ -75,7 +86,7 @@ private: // class AmpCC1 : public AmpCC { public: - AmpCC1( Mustang * theAmp ) : AmpCC(theAmp) {} + AmpCC1( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : AmpCC(theAmp,model,theSlot) {} private: // Presence virtual int cc78( int value ) { return continuous_control( 0x07, 0x07, 0x0c, value );} @@ -88,7 +99,7 @@ private: // class AmpCC2 : public AmpCC { public: - AmpCC2( Mustang * theAmp ) : AmpCC(theAmp) {} + AmpCC2( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : AmpCC(theAmp,model,theSlot) {} private: // Gain2 virtual int cc78( int value ) { return continuous_control( 0x02, 0x02, 0x0c, value );} @@ -101,7 +112,7 @@ private: // class AmpCC3 : public AmpCC { public: - AmpCC3( Mustang * theAmp ) : AmpCC(theAmp) {} + AmpCC3( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : AmpCC(theAmp,model,theSlot) {} private: // Cut virtual int cc78( int value ) { return continuous_control( 0x07, 0x07, 0x0c, value );} @@ -117,7 +128,7 @@ private: // class AmpCC4 : public AmpCC { public: - AmpCC4( Mustang * theAmp ) : AmpCC(theAmp) {} + AmpCC4( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : AmpCC(theAmp,model,theSlot) {} private: // Presence virtual int cc78( int value ) { return continuous_control( 0x07, 0x07, 0x0c, value );} @@ -130,7 +141,7 @@ private: // class AmpCC5 : public AmpCC { public: - AmpCC5( Mustang * theAmp ) : AmpCC(theAmp) {} + AmpCC5( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : AmpCC(theAmp,model,theSlot) {} private: // No sag / bias virtual int cc74( int value ) { return 0;} @@ -145,7 +156,7 @@ private: // class AmpCC6 : public AmpCC { public: - AmpCC6( Mustang * theAmp ) : AmpCC(theAmp) {} + AmpCC6( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : AmpCC(theAmp,model,theSlot) {} private: // Master Volume virtual int cc79( int value ) { return continuous_control( 0x03, 0x03, 0x0c, value );} @@ -156,7 +167,7 @@ private: // class AmpCC7 : public AmpCC { public: - AmpCC7( Mustang * theAmp ) : AmpCC(theAmp) {} + AmpCC7( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : AmpCC(theAmp,model,theSlot) {} private: // Presence virtual int cc78( int value ) { return continuous_control( 0x07, 0x07, 0x0c, value );} @@ -167,7 +178,7 @@ private: // class NullAmpCC : public AmpCC { public: - NullAmpCC( Mustang * theAmp ) : AmpCC(theAmp) {} + NullAmpCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : AmpCC(theAmp,model,theSlot) {} private: virtual int cc69( int value ) { return 0;} virtual int cc70( int value ) { return 0;} diff --git a/amp_models.cpp b/amp_models.cpp new file mode 100644 index 0000000..6ebfc3a --- /dev/null +++ b/amp_models.cpp @@ -0,0 +1,22 @@ +#include "amp_models.h" + +const unsigned char f57_deluxe_id[] = { 0x67, 0x00 }; +const unsigned char f59_bassman_id[] = { 0x64, 0x00 }; +const unsigned char f57_champ_id[] = { 0x7c, 0x00 }; +const unsigned char f65_deluxe_id[] = { 0x53, 0x00 }; +const unsigned char f65_princeton_id[] = { 0x6a, 0x00 }; +const unsigned char f65_twin_id[] = { 0x75, 0x00 }; +const unsigned char f_supersonic_id[] = { 0x72, 0x00 }; +const unsigned char brit_60s_id[] = { 0x61, 0x00 }; +const unsigned char brit_70s_id[] = { 0x79, 0x00 }; +const unsigned char brit_80s_id[] = { 0x5e, 0x00 }; +const unsigned char us_90s_id[] = { 0x5d, 0x00 }; +const unsigned char metal_2k_id[] = { 0x6d, 0x00 }; + +// v2 only +const unsigned char studio_preamp_id[] = { 0xf1, 0x00 }; +const unsigned char f57_twin_id[] = { 0xf6, 0x00 }; +const unsigned char s60s_thrift_id[] = { 0xf9, 0x00 }; +const unsigned char brit_watt_id[] = { 0xff, 0x00 }; +const unsigned char brit_color_id[] = { 0xfc, 0x00 }; + diff --git a/amp_models.h b/amp_models.h new file mode 100644 index 0000000..ecfd3c1 --- /dev/null +++ b/amp_models.h @@ -0,0 +1,24 @@ +#ifndef AMP_MODELS_H +#define AMP_MODELS_H + +extern const unsigned char f57_deluxe_id[]; +extern const unsigned char f59_bassman_id[]; +extern const unsigned char f57_champ_id[]; +extern const unsigned char f65_deluxe_id[]; +extern const unsigned char f65_princeton_id[]; +extern const unsigned char f65_twin_id[]; +extern const unsigned char f_supersonic_id[]; +extern const unsigned char brit_60s_id[]; +extern const unsigned char brit_70s_id[]; +extern const unsigned char brit_80s_id[]; +extern const unsigned char us_90s_id[]; +extern const unsigned char metal_2k_id[]; + +// v2 only +extern const unsigned char studio_preamp_id[]; +extern const unsigned char f57_twin_id[]; +extern const unsigned char s60s_thrift_id[]; +extern const unsigned char brit_watt_id[]; +extern const unsigned char brit_color_id[]; + +#endif diff --git a/constants.h b/constants.h new file mode 100644 index 0000000..53b384b --- /dev/null +++ b/constants.h @@ -0,0 +1,62 @@ +#ifndef CONSTANTS_H +#define CONSTANTS_H + +// USB vendor id +#define FENDER_VID 0x1ed8 + +// USB product ids +#define MI_II_V1 0x0004 +#define MIII_IV_V_V1 0x0005 +#define M_BRONCO_40 0x000a +#define M_MINI 0x0010 +#define M_FLOOR 0x0012 +#define MI_II_V2 0x0014 +#define MIII_IV_V_V2 0x0016 + +#define DSP 2 +#define PATCH_SLOT 4 +#define EFFECT 16 +#define FXSLOT 18 + +// direct control fields +#define FAMILY 2 +#define ACTIVE_INVERT 3 + +// Offset to current device model for any state structure +#define MODEL 16 +#define MODELX 17 + +// Index into current state structure +#define AMP_STATE 0 +#define STOMP_STATE 1 +#define MOD_STATE 2 +#define DELAY_STATE 3 +#define REVERB_STATE 4 +#define PEDAL_STATE 5 + +// DSP Category +#define AMP_DSP 5 +#define STOMP_DSP 6 +#define MOD_DSP 7 +#define DELAY_DSP 8 +#define REVERB_DSP 9 + +// DSP Family (used for direct parm set) - Effectively DSP - 3 +#define STOMP_FAM 3 +#define MOD_FAM 4 +#define DELAY_FAM 5 +#define REVERB_FAM 6 + +// Reverb model id values +#define SM_HALL_ID 0x0024 +#define LG_HALL_ID 0x003a +#define SM_ROOM_ID 0x0026 +#define LG_ROOM_ID 0x003b +#define SM_PLATE_ID 0x004e +#define LG_PLATE_ID 0x004b +#define AMBIENT_ID 0x004c +#define ARENA_ID 0x004d +#define SPRING_63_ID 0x0021 +#define SPRING_65_ID 0x000b + +#endif diff --git a/data_structs.h b/data_structs.h deleted file mode 100644 index 2bdb355..0000000 --- a/data_structs.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef DATA_STRUCTS_H -#define DATA_STRUCTS_H - -struct amp_settings -{ - unsigned char amp_num; - unsigned char gain; - unsigned char volume; - unsigned char treble; - unsigned char middle; - unsigned char bass; - unsigned char cabinet; - unsigned char noise_gate; - unsigned char master_vol; - unsigned char gain2; - unsigned char presence; - unsigned char threshold; - unsigned char depth; - unsigned char bias; - unsigned char sag; - bool brightness; - unsigned char usb_gain; -}; - -struct fx_pedal_settings -{ - unsigned char fx_slot; - unsigned char effect_num; - unsigned char knob1; - unsigned char knob2; - unsigned char knob3; - unsigned char knob4; - unsigned char knob5; - unsigned char knob6; - bool put_post_amp; -}; - -#endif // DATA_STRUCTS_H diff --git a/delay.cpp b/delay.cpp index d1469ad..60f99e4 100644 --- a/delay.cpp +++ b/delay.cpp @@ -1,6 +1,7 @@ #include "delay.h" #include "mustang.h" +#include "constants.h" int DelayCC::continuous_control( int parm5, int parm6, int parm7, int value ) { diff --git a/delay.h b/delay.h index dbf6f0f..9ea57e6 100644 --- a/delay.h +++ b/delay.h @@ -3,20 +3,31 @@ #ifndef _DELAY_H #define _DELAY_H +#include + class Mustang; class DelayCC { protected: Mustang * amp; + unsigned char model[2]; + unsigned char slot; 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) {} + DelayCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : + amp(theAmp), + slot(theSlot) + { + memcpy( this->model, model, 2 ); + } int dispatch( int cc, int value ); + const unsigned char *getModel( void ) { return model;} + const unsigned char getSlot( void ) { return slot;} private: // Level @@ -33,7 +44,7 @@ private: class MonoDelayCC : public DelayCC { public: - MonoDelayCC( Mustang * theAmp ) : DelayCC(theAmp) {} + MonoDelayCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : DelayCC(theAmp,model,theSlot) {} private: // Feedback virtual int cc51( int value ) { return continuous_control( 0x02, 0x02, 0x01, value );} @@ -48,7 +59,7 @@ private: class EchoFilterCC : public DelayCC { public: - EchoFilterCC( Mustang * theAmp ) : DelayCC(theAmp) {} + EchoFilterCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : DelayCC(theAmp,model,theSlot) {} private: // Feedback virtual int cc51( int value ) { return continuous_control( 0x02, 0x02, 0x01, value );} @@ -63,7 +74,7 @@ private: class MultitapDelayCC : public DelayCC { public: - MultitapDelayCC( Mustang * theAmp ) : DelayCC(theAmp) {} + MultitapDelayCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : DelayCC(theAmp,model,theSlot) {} private: // Delay Time virtual int cc50( int value ) { return continuous_control( 0x01, 0x01, 0x08, value );} @@ -83,7 +94,7 @@ private: class PingPongDelayCC : public DelayCC { public: - PingPongDelayCC( Mustang * theAmp ) : DelayCC(theAmp) {} + PingPongDelayCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : DelayCC(theAmp,model,theSlot) {} private: // Feedback virtual int cc51( int value ) { return continuous_control( 0x02, 0x02, 0x01, value );} @@ -98,7 +109,7 @@ private: class DuckingDelayCC : public DelayCC { public: - DuckingDelayCC( Mustang * theAmp ) : DelayCC(theAmp) {} + DuckingDelayCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : DelayCC(theAmp,model,theSlot) {} private: // Feedback virtual int cc51( int value ) { return continuous_control( 0x02, 0x02, 0x01, value );} @@ -113,7 +124,7 @@ private: class ReverseDelayCC : public DelayCC { public: - ReverseDelayCC( Mustang * theAmp ) : DelayCC(theAmp) {} + ReverseDelayCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : DelayCC(theAmp,model,theSlot) {} private: // FFdbk virtual int cc51( int value ) { return continuous_control( 0x02, 0x02, 0x01, value );} @@ -128,7 +139,7 @@ private: class TapeDelayCC : public DelayCC { public: - TapeDelayCC( Mustang * theAmp ) : DelayCC(theAmp) {} + TapeDelayCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : DelayCC(theAmp,model,theSlot) {} private: // Feedback virtual int cc51( int value ) { return continuous_control( 0x02, 0x02, 0x01, value );} @@ -143,7 +154,7 @@ private: class StereoTapeDelayCC : public DelayCC { public: - StereoTapeDelayCC( Mustang * theAmp ) : DelayCC(theAmp) {} + StereoTapeDelayCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : DelayCC(theAmp,model,theSlot) {} private: // Feedback virtual int cc51( int value ) { return continuous_control( 0x02, 0x02, 0x01, value );} @@ -158,7 +169,7 @@ private: class NullDelayCC : public DelayCC { public: - NullDelayCC( Mustang * theAmp ) : DelayCC(theAmp) {} + NullDelayCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : DelayCC(theAmp,model,theSlot) {} private: virtual int cc49( int value ) { return 0;} virtual int cc50( int value ) { return 0;} diff --git a/delay_models.cpp b/delay_models.cpp new file mode 100644 index 0000000..ef6ae4b --- /dev/null +++ b/delay_models.cpp @@ -0,0 +1,12 @@ +#include "delay_models.h" + +const unsigned char mono_dly_id[] = { 0x16, 0x00 }; +const unsigned char mono_filter_id[] = { 0x43, 0x00 }; +const unsigned char st_filter_id[] = { 0x48, 0x00 }; +const unsigned char mtap_dly_id[] = { 0x44, 0x00 }; +const unsigned char pong_dly_id[] = { 0x45, 0x00 }; +const unsigned char duck_dly_id[] = { 0x15, 0x00 }; +const unsigned char reverse_dly_id[] = { 0x46, 0x00 }; +const unsigned char tape_dly_id[] = { 0x2b, 0x00 }; +const unsigned char st_tape_dly_id[] = { 0x2a, 0x00 }; + diff --git a/delay_models.h b/delay_models.h new file mode 100644 index 0000000..bbfa0e5 --- /dev/null +++ b/delay_models.h @@ -0,0 +1,14 @@ +#ifndef DELAY_MODELS_H +#define DELAY_MODELS_H + +extern const unsigned char mono_dly_id[]; +extern const unsigned char mono_filter_id[]; +extern const unsigned char st_filter_id[]; +extern const unsigned char mtap_dly_id[]; +extern const unsigned char pong_dly_id[]; +extern const unsigned char duck_dly_id[]; +extern const unsigned char reverse_dly_id[]; +extern const unsigned char tape_dly_id[]; +extern const unsigned char st_tape_dly_id[]; + +#endif diff --git a/effects_enum.h b/effects_enum.h deleted file mode 100644 index c70d99b..0000000 --- a/effects_enum.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef EFFECTS_ENUM_H -#define EFFECTS_ENUM_H - -// enums used for switches (looks nicer -// and is more practical than numbers) - -// list of all amplifiers -enum amps -{ - STUDIO_PREAMP, - FENDER_57_CHAMP, - FENDER_57_DELUXE, - FENDER_57_TWIN, - FENDER_59_BASSMAN, - FENDER_65_PRINCETON, - FENDER_65_DELUXE_REVERB, - FENDER_65_TWIN_REVERB, - S60S_THRIFT, - BRITISH_WATTS, - BRITISH_60S, - BRITISH_70S, - BRITISH_80S, - BRITISH_COLOUR, - FENDER_SUPER_SONIC, - AMERICAN_90S, - METAL_2000 - -}; - -// list of all effects -enum effects -{ - EMPTY, - RANGER, - GREENBOX, - OVERDRIVE, - FUZZ, - ORANGEBOX, - BLACKBOX, - BIG_FUZZ, - WAH, - TOUCH_WAH, - FUZZ_TOUCH_WAH, - SIMPLE_COMP, - COMPRESSOR, - - SINE_CHORUS, - TRIANGLE_CHORUS, - SINE_FLANGER, - TRIANGLE_FLANGER, - VIBRATONE, - VINTAGE_TREMOLO, - SINE_TREMOLO, - RING_MODULATOR, - STEP_FILTER, - PHASER, - MOD_WAH, - MOD_TOUCH_WAH, - DIATONIC_PITCH_SHIFTER, - PITCH_SHIFTER, - - MONO_DELAY, - MONO_ECHO_FILTER, - STEREO_ECHO_FILTER, - MULTITAP_DELAY, - PING_PONG_DELAY, - DUCKING_DELAY, - REVERSE_DELAY, - TAPE_DELAY, - STEREO_TAPE_DELAY, - - SMALL_HALL_REVERB, - LARGE_HALL_REVERB, - SMALL_ROOM_REVERB, - LARGE_ROOM_REVERB, - SMALL_PLATE_REVERB, - LARGE_PLATE_REVERB, - AMBIENT_REVERB, - ARENA_REVERB, - FENDER_63_SPRING_REVERB, - FENDER_65_SPRING_REVERB -}; - -// list of all cabinets -enum cabinets -{ - OFF, - cab57DLX, - cabBSSMN, - cab65DLX, - cab65PRN, - cabCHAMP, - cab4x12M, - cab2x12C, - cab4x12G, - cab65TWN, - cab4x12V, - cabSS212, - cabSS112 -}; - -#endif // EFFECTS_ENUM_H diff --git a/mod.cpp b/mod.cpp index 063f281..300e722 100644 --- a/mod.cpp +++ b/mod.cpp @@ -1,6 +1,7 @@ #include "mod.h" #include "mustang.h" +#include "constants.h" int ModCC::continuous_control( int parm5, int parm6, int parm7, int value ) { diff --git a/mod.h b/mod.h index e901fa2..ea67298 100644 --- a/mod.h +++ b/mod.h @@ -3,20 +3,31 @@ #ifndef _MOD_H #define _MOD_H +#include + class Mustang; class ModCC { protected: Mustang * amp; + unsigned char model[2]; + unsigned char slot; int continuous_control( int parm5, int parm6, int parm7, int value ); int discrete_control( int parm5, int parm6, int parm7, int value ); public: - ModCC( Mustang * theAmp ) : amp(theAmp) {} + ModCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : + amp(theAmp), + slot(theSlot) + { + memcpy( this->model, model, 2 ); + } int dispatch( int cc, int value ); + const unsigned char *getModel( void ) { return model;} + const unsigned char getSlot( void ) { return slot;} private: virtual int cc39( int value ) = 0; @@ -29,7 +40,7 @@ private: class ChorusCC : public ModCC { public: - ChorusCC( Mustang * theAmp ) : ModCC(theAmp) {} + ChorusCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : ModCC(theAmp,model,theSlot) {} private: // Level virtual int cc39( int value ) { return continuous_control( 0x00, 0x00, 0x01, value );} @@ -46,7 +57,7 @@ private: class FlangerCC : public ModCC { public: - FlangerCC( Mustang * theAmp ) : ModCC(theAmp) {} + FlangerCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : ModCC(theAmp,model,theSlot) {} private: // Level virtual int cc39( int value ) { return continuous_control( 0x00, 0x00, 0x01, value );} @@ -63,7 +74,7 @@ private: class VibratoneCC : public ModCC { public: - VibratoneCC( Mustang * theAmp ) : ModCC(theAmp) {} + VibratoneCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : ModCC(theAmp,model,theSlot) {} private: // Level virtual int cc39( int value ) { return continuous_control( 0x00, 0x00, 0x01, value );} @@ -80,7 +91,7 @@ private: class TremCC : public ModCC { public: - TremCC( Mustang * theAmp ) : ModCC(theAmp) {} + TremCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : ModCC(theAmp,model,theSlot) {} private: // Level virtual int cc39( int value ) { return continuous_control( 0x00, 0x00, 0x01, value );} @@ -97,7 +108,7 @@ private: class RingModCC : public ModCC { public: - RingModCC( Mustang * theAmp ) : ModCC(theAmp) {} + RingModCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : ModCC(theAmp,model,theSlot) {} private: // Level virtual int cc39( int value ) { return continuous_control( 0x00, 0x00, 0x01, value );} @@ -117,7 +128,7 @@ private: class StepFilterCC : public ModCC { public: - StepFilterCC( Mustang * theAmp ) : ModCC(theAmp) {} + StepFilterCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : ModCC(theAmp,model,theSlot) {} private: // Level virtual int cc39( int value ) { return continuous_control( 0x00, 0x00, 0x01, value );} @@ -134,7 +145,7 @@ private: class PhaserCC : public ModCC { public: - PhaserCC( Mustang * theAmp ) : ModCC(theAmp) {} + PhaserCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : ModCC(theAmp,model,theSlot) {} private: // Level virtual int cc39( int value ) { return continuous_control( 0x00, 0x00, 0x01, value );} @@ -154,7 +165,7 @@ private: class PitchShifterCC : public ModCC { public: - PitchShifterCC( Mustang * theAmp ) : ModCC(theAmp) {} + PitchShifterCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : ModCC(theAmp,model,theSlot) {} private: // Level virtual int cc39( int value ) { return continuous_control( 0x00, 0x00, 0x01, value );} @@ -171,7 +182,7 @@ private: // Wah + Touch Wah class ModWahCC : public ModCC { public: - ModWahCC( Mustang * theAmp ) : ModCC(theAmp) {} + ModWahCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : ModCC(theAmp,model,theSlot) {} private: // Mix virtual int cc39( int value ) { return continuous_control( 0x00, 0x00, 0x01, value );} @@ -191,7 +202,7 @@ private: class DiatonicShiftCC : public ModCC { public: - DiatonicShiftCC( Mustang * theAmp ) : ModCC(theAmp) {} + DiatonicShiftCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : ModCC(theAmp,model,theSlot) {} private: // Mix virtual int cc39( int value ) { return continuous_control( 0x00, 0x00, 0x01, value );} @@ -217,7 +228,7 @@ private: class NullModCC : public ModCC { public: - NullModCC( Mustang * theAmp ) : ModCC(theAmp) {} + NullModCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : ModCC(theAmp,model,theSlot) {} private: virtual int cc39( int value ) { return 0;} virtual int cc40( int value ) { return 0;} diff --git a/mod_models.cpp b/mod_models.cpp new file mode 100644 index 0000000..949802a --- /dev/null +++ b/mod_models.cpp @@ -0,0 +1,17 @@ +#include "mod_models.h" + +const unsigned char sine_chorus_id[] = { 0x12, 0x00 }; +const unsigned char tri_chorus_id[] = { 0x13, 0x00 }; +const unsigned char sine_flange_id[] = { 0x18, 0x00 }; +const unsigned char tri_flange_id[] = { 0x19, 0x00 }; +const unsigned char vibratone_id[] = { 0x2d, 0x00 }; +const unsigned char vint_trem_id[] = { 0x40, 0x00 }; +const unsigned char sine_trem_id[] = { 0x41, 0x00 }; +const unsigned char ring_mod_id[] = { 0x22, 0x00 }; +const unsigned char step_filt_id[] = { 0x29, 0x00 }; +const unsigned char phaser_id[] = { 0x4f, 0x00 }; + +const unsigned char pitch_shift_id[] = { 0x1f, 0x00 }; +const unsigned char m_wah_id[] = { 0xf4, 0x00 }; +const unsigned char m_touch_wah_id[] = { 0xf5, 0x00 }; +const unsigned char dia_pitch_id[] = { 0x1f, 0x10 }; diff --git a/mod_models.h b/mod_models.h new file mode 100644 index 0000000..2c8f45c --- /dev/null +++ b/mod_models.h @@ -0,0 +1,22 @@ +// -*-c++-*- + +#ifndef MOD_MODELS_H +#define MOD_MODELS_H + +extern const unsigned char sine_chorus_id[]; +extern const unsigned char tri_chorus_id[]; +extern const unsigned char sine_flange_id[]; +extern const unsigned char tri_flange_id[]; +extern const unsigned char vibratone_id[]; +extern const unsigned char vint_trem_id[]; +extern const unsigned char sine_trem_id[]; +extern const unsigned char ring_mod_id[]; +extern const unsigned char step_filt_id[]; +extern const unsigned char phaser_id[]; +extern const unsigned char pitch_shift_id[]; +// v2 only +extern const unsigned char m_wah_id[]; +extern const unsigned char m_touch_wah_id[]; +extern const unsigned char dia_pitch_id[]; + +#endif diff --git a/mustang.cpp b/mustang.cpp index 8b6ca3a..24f8637 100644 --- a/mustang.cpp +++ b/mustang.cpp @@ -1,5 +1,7 @@ #include "mustang.h" -#include + +#include + #include #include "magic.h" @@ -16,1646 +18,1138 @@ #include "mod_defaults.h" #include "stomp_defaults.h" -Mustang::usb_id Mustang::ids[] = { - { OLD_USB_PID, 0x03, false }, - { NEW_USB_PID, 0xc1, false }, - { V2_USB_PID, 0x03, false }, - { MINI_USB_PID, 0x03, false }, - { FLOOR_USB_PID, 0x03, false }, - { BRONCO40_USB_PID, 0x03, false }, - { V2_III_PID, 0xc1, true }, - { V2_IV_PID, 0xc1, true }, +#include "amp_models.h" +#include "stomp_models.h" +#include "mod_models.h" +#include "delay_models.h" + +// Parameter report (preset names + DSP states) +const unsigned char Mustang::state_prefix[] = { 0x1c, 0x01 }; + +// End of full parameter dump +const unsigned char Mustang::parms_done[] = { 0xff, 0x01 }; + +// Acknowledge tuner toggle +const unsigned char Mustang::tuner_ack[] = { 0x0a, 0x01 }; + +// Tuner display update +const unsigned char Mustang::tuner_prefix[] = { 0x0b, 0x01 }; + +// Acknowledge model-select +const unsigned char Mustang::select_ack[] = { 0x00, 0x00, 0x1c }; + +// Acknowledge CC +const unsigned char Mustang::cc_ack[] = { 0x00, 0x00, 0x05 }; + + +const Mustang::usb_id Mustang::amp_ids[] = { + { MI_II_V1, 0x03, false }, + { MIII_IV_V_V1, 0xc1, false }, + { M_BRONCO_40, 0x03, false }, + { M_MINI, 0x03, false }, + { M_FLOOR, 0x03, false }, + { MI_II_V2, 0xc1, true }, + { MIII_IV_V_V2, 0xc1, true }, { 0, 0x00, false } }; - -Mustang::Mustang() -{ - amp_hand = NULL; - curr_amp = NULL; - tuner_active = false; - isV2 = false; - - // "apply efect" command - memset(execute, 0x00, LENGTH); - execute[0] = 0x1c; - execute[1] = 0x03; - memset(prev_array, 0x00, LENGTH*4); - for(int i = 0; i < 4; i++) - { - prev_array[i][0] = 0x1c; - prev_array[i][1] = 0x03; - prev_array[i][6] = prev_array[i][7] = prev_array[i][21] = 0x01; - prev_array[i][20] = 0x08; - prev_array[i][FXSLOT] = 0xff; - } -} - -Mustang::~Mustang() -{ - this->stop_amp(); -} - -int Mustang::start_amp(void) -{ - int ret, received; - static int init_value = -1; - unsigned char array[LENGTH]; - - if(amp_hand == NULL) - { - // initialize libusb - ret = libusb_init(NULL); - if (ret) - return ret; - - for ( int idx=0; ids[idx].pid != 0; idx++ ) { - if ( (amp_hand = libusb_open_device_with_vid_pid(NULL, USB_VID, ids[idx].pid)) != NULL ) { - init_value = ids[idx].init_value; - isV2 = ids[idx].isV2; - break; - } - } - - if ( init_value < 0 ) { - // No amp found - libusb_exit( NULL ); - fprintf( stderr, "S - No Mustang USB device found\n" ); - return -100; - } - - // detach kernel driver - ret = libusb_kernel_driver_active(amp_hand, 0); - if(ret) - { - ret = libusb_detach_kernel_driver(amp_hand, 0); - if(ret) - { - stop_amp(); - return ret; - } - } - - // claim the device - ret = libusb_claim_interface(amp_hand, 0); - if(ret) - { - stop_amp(); - return ret; - } - } - - // initialization which is needed if you want - // to get any replies from the amp in the future - memset(array, 0x00, LENGTH); - array[1] = 0xc3; - libusb_interrupt_transfer(amp_hand, 0x01, array, LENGTH, &received, TMOUT); - libusb_interrupt_transfer(amp_hand, 0x81, array, LENGTH, &received, TMOUT); - - memset(array, 0x00, LENGTH); - array[0] = 0x1a; - array[1] = init_value; - - libusb_interrupt_transfer(amp_hand, 0x01, array, LENGTH, &received, TMOUT); - libusb_interrupt_transfer(amp_hand, 0x81, array, LENGTH, &received, TMOUT); - - memset(array, 0x00, LENGTH); - array[0] = 0xff; - array[1] = 0xc1; - - // Request parameter dump from amplifier - libusb_interrupt_transfer(amp_hand, 0x01, array, LENGTH, &received, TMOUT); - - handle_parm_dump(); - - return 0; -} - -void Mustang::handle_parm_dump() -{ - int ret, received; - unsigned char array[LENGTH]; - unsigned char received_data[296][LENGTH], data[7][LENGTH]; - memset(received_data, 0x00, 296*LENGTH); - - int i = 0, j = 0; - - // Count probably varies by model. Brute-force flush appears to create problems - // so we'll need to get this right case by case. - for(i = 0; i < 210; i++) - { - int rc = libusb_interrupt_transfer(amp_hand, 0x81, array, LENGTH, &received, TMOUT); - if (rc) fprintf( stderr, "DEBUG: Timeout. i = %d, rc = %d\n", i, rc ); - memcpy(received_data[i], array, LENGTH); - } - - // fprintf( stderr, "DEBUG: Packet count = %d\n", i ); - - int max_to_receive; - i > 143 ? max_to_receive = 200 : max_to_receive = 48; - - // List of preset names - for(i = 0, j = 0; ihandleInput(); + return NULL; } - -int Mustang::tunerMode( int value ) -{ - int ret, received; - unsigned char array[LENGTH]; - memset(array, 0x00, LENGTH); - - array[0] = 0x0a; - array[1] = 0x01; - - // This is a bit odd. When turning ON the tuner, the amp responds - // with a complete parameter dump reflecting all null devices - // (basically useless). When turning it off, we get only a single - // response message. - // - if ( value > 63 && value <= 127 ) { - // Tuner on - array[2] = array[3] = array[4] = 0x01; - ret = libusb_interrupt_transfer(amp_hand, 0x01, array, LENGTH, &received, TMOUT); - - int i = 0; - for(i = 0; i < 210; i++) { - int rc = libusb_interrupt_transfer(amp_hand, 0x81, array, LENGTH, &received, TMOUT); - if (rc) fprintf( stderr, "DEBUG: Timeout. i = %d, rc = %d\n", i, rc ); - } - tuner_active = true; - } - else if ( value >= 0 && value <= 63 ) { - // Tuner off - ret = libusb_interrupt_transfer(amp_hand, 0x01, array, LENGTH, &received, TMOUT); - libusb_interrupt_transfer(amp_hand, 0x81, array, LENGTH, &received, TMOUT); - sleep( 1 ); - tuner_active = false; - } - - return ret; -} - - -void Mustang::updateAmpObj(void) { - - int curr = curr_state[AMP_STATE][MODEL]; - AmpCC * new_amp = NULL; - - switch (curr) { - case 0: - // No amp - break; - - case F57_DELUXE_ID: - case F57_CHAMP_ID: - case F65_DELUXE_ID: - case F65_PRINCETON_ID: - case F65_TWIN_ID: - case S60S_THRIFT_ID: - new_amp = new AmpCC(this); - break; - case F59_BASSMAN_ID: - case BRIT_70S_ID: - new_amp = new AmpCC1(this); - break; - - case F_SUPERSONIC_ID: - new_amp = new AmpCC2(this); - break; - - case BRIT_60S_ID: - new_amp = new AmpCC3(this); - break; - - case BRIT_80S_ID: - case US_90S_ID: - case METAL_2K_ID: - case BRIT_WATT_ID: - new_amp = new AmpCC4(this); - break; - - case STUDIO_PREAMP_ID: - new_amp = new AmpCC5(this); - break; - case BRIT_COLOR_ID: - new_amp = new AmpCC6(this); - break; - - case F57_TWIN_ID: - new_amp = new AmpCC7(this); - break; - - default: - fprintf( stderr, "W - Amp id %x not supported yet\n", curr ); - break; +void +Mustang::handleInput( void ) { + + int rc; + unsigned char read_buf[64]; + int total_count = 0; + + while ( 1 ) { + int count; + rc = libusb_interrupt_transfer( usb_io, USB_IN, read_buf, 64, &count, USB_TIMEOUT_MS ); + total_count += count; + + // Check for exit flag + pthread_mutex_lock( &shutdown_lock ); + bool finished = want_shutdown; + pthread_mutex_unlock( &shutdown_lock ); + if ( finished ) break; + + if ( rc!=0 ) { + // Retry on timeout, otherwise exit + if ( rc==LIBUSB_ERROR_TIMEOUT ) continue; + else break; } - if ( new_amp!=NULL ) { - delete curr_amp; - curr_amp = new_amp; - } -} + // Retry on short read + if ( total_count!=64 ) continue; + total_count = 0; - -void Mustang::updateReverbObj(void) { - - int curr = curr_state[REVERB_STATE][MODEL]; - - switch (curr) { - case 0: - break; - - default: - delete curr_reverb; - curr_reverb = new ReverbCC( this ); - break; - } -} - - -void Mustang::updateDelayObj(void) { - - int curr = curr_state[DELAY_STATE][MODEL]; - DelayCC * new_delay = NULL; - - switch (curr) { - case 0: - break; - - case MONO_DLY_ID: - new_delay = new MonoDelayCC(this); - break; - - case MONO_FILTER_ID: - case ST_FILTER_ID: - new_delay = new EchoFilterCC(this); - break; - - case MTAP_DLY_ID: - new_delay = new MultitapDelayCC(this); - break; - - case PONG_DLY_ID: - new_delay = new PingPongDelayCC(this); - break; - - case DUCK_DLY_ID: - new_delay = new DuckingDelayCC(this); - break; - - case REVERSE_DLY_ID: - new_delay = new ReverseDelayCC(this); - break; - - case TAPE_DLY_ID: - new_delay = new TapeDelayCC(this); - break; - - case ST_TAPE_DLY_ID: - new_delay = new StereoTapeDelayCC(this); - break; - - default: - fprintf( stderr, "W - Delay id %x not supported yet\n", curr ); - break; - } - - if ( new_delay!=NULL ) { - delete curr_delay; - curr_delay = new_delay; - } -} - - -void Mustang::updateModObj(void) { - - int curr = curr_state[MOD_STATE][MODEL]; - ModCC * new_mod = NULL; - - switch (curr) { - case 0: - break; - - case SINE_CHORUS_ID: - case TRI_CHORUS_ID: - new_mod = new ChorusCC(this); - break; - - case SINE_FLANGE_ID: - case TRI_FLANGE_ID: - new_mod = new FlangerCC(this); - break; - - case VIBRATONE_ID: - new_mod = new VibratoneCC(this); - break; - - case VINT_TREM_ID: - case SINE_TREM_ID: - new_mod = new TremCC(this); - break; - - case RING_MOD_ID: - new_mod = new RingModCC(this); - break; - - case STEP_FILT_ID: - new_mod = new StepFilterCC(this); - break; - - case PHASER_ID: - new_mod = new PhaserCC(this); - break; - - case PITCH_SHIFT_ID: - { - int xtra = curr_state[MOD_STATE][MODELX]; - if ( xtra == 0 ) new_mod = new PitchShifterCC(this); - else if ( xtra == 0x10 ) new_mod = new DiatonicShiftCC(this); - } - break; - - case M_WAH_ID: - case M_TOUCH_WAH_ID: - new_mod = new ModWahCC(this); - break; - - default: - fprintf( stderr, "W - Mod id %x not supported yet\n", curr ); - break; - } - - if ( new_mod!=NULL ) { - delete curr_mod; - curr_mod = new_mod; - } -} - - -void Mustang::updateStompObj(void) { - - int curr = curr_state[STOMP_STATE][MODEL]; - StompCC * new_stomp = NULL; - - switch (curr) { - case 0: - break; - - case OVERDRIVE_ID: - new_stomp = new OverdriveCC(this); - break; - - case WAH_ID: - case TOUCH_WAH_ID: - new_stomp = new WahCC(this); - break; - - case FUZZ_ID: - new_stomp = new FuzzCC(this); - break; - - case FUZZ_TWAH_ID: - new_stomp = new FuzzTouchWahCC(this); - break; - - case SIMPLE_COMP_ID: - new_stomp = new SimpleCompCC(this); - break; - - case COMP_ID: - new_stomp = new CompCC(this); - break; - - case RANGE_BOOST_ID: - new_stomp = new RangerCC(this); - break; - - case GREEN_BOX_ID: - new_stomp = new GreenBoxCC(this); - break; - - case ORANGE_BOX_ID: - new_stomp = new OrangeBoxCC(this); - break; - - case BLACK_BOX_ID: - new_stomp = new BlackBoxCC(this); - break; - - case BIG_FUZZ_ID: - new_stomp = new BigFuzzCC(this); - break; - - default: - fprintf( stderr, "W - Stomp id %x not supported yet\n", curr ); - break; - } - - if ( new_stomp!=NULL ) { - delete curr_stomp; - curr_stomp = new_stomp; - } -} - - -int Mustang::effect_toggle(int cc, int value) -{ - if ( tuner_active ) return 0; - - int ret, received; - unsigned char array[LENGTH]; - - // Translate 23..26 --> 2..5 (current state index) - int state_index = cc - 21; - int state; - if ( value >= 0 && value <= 63 ) state = 1; - else if ( value > 63 && value <= 127 ) state = 0; - - memset(array, 0x00, LENGTH); - array[0] = 0x19; - array[1] = 0xc3; - // Translate DSP to family - array[FAMILY] = curr_state[state_index][DSP] - 3; - // Invert logic - array[ACTIVE_INVERT] = state; - array[FXSLOT] = curr_state[state_index][FXSLOT]; -#if 0 - for ( int i=0; i<15; i++ ) fprintf( stderr, "%02x ", array[i] ); +#if 0 + for ( int i=0; i<64; i++ ) fprintf( stderr, "%02x ", read_buf[i] ); fprintf( stderr, "\n" ); #endif - ret = libusb_interrupt_transfer(amp_hand, 0x01, array, LENGTH, &received, TMOUT); - // Note: Toggle gets three response packets - for (int i=0; i < 3; i++) { - libusb_interrupt_transfer(amp_hand, 0x81, array, LENGTH, &received, TMOUT); + if ( 0==memcmp(read_buf,state_prefix,2) ) { + // Only care about amp state messages, and not even all of them... + int dsp_category = read_buf[2]; + switch( dsp_category ) { + case 0x04: + { + // Preset name + int idx = read_buf[4]; + pthread_mutex_lock( &preset_names_sync.lock ); + + strncpy( preset_names[idx], (const char *)read_buf+16, 32 ); + preset_names[idx][32] = '\0'; + // Always take the most recent one as the current preset. This + // will properly account for its appearance at the end of a complete + // parm dump or when manual patch change occurs. + curr_preset_idx = idx; + + preset_names_sync.value = true; + pthread_cond_signal( &preset_names_sync.cond ); + pthread_mutex_unlock( &preset_names_sync.lock ); + break; + } + case 0x05: + { + // AMP + // DSP parms (make 0x05..0x0a normal to zero) + int idx = dsp_category - 5; + pthread_mutex_lock( &dsp_sync[idx].lock ); + + memcpy( dsp_parms[idx], (const char *)read_buf, 64 ); + updateAmpObj( read_buf ); + + dsp_sync[idx].value = true; + pthread_cond_signal( &dsp_sync[idx].cond ); + pthread_mutex_unlock( &dsp_sync[idx].lock ); + break; + } + case 0x06: + { + // STOMP + int idx = dsp_category - 5; + pthread_mutex_lock( &dsp_sync[idx].lock ); + + memcpy( dsp_parms[idx], (const char *)read_buf, 64 ); + updateStompObj( read_buf ); + + dsp_sync[idx].value = true; + pthread_cond_signal( &dsp_sync[idx].cond ); + pthread_mutex_unlock( &dsp_sync[idx].lock ); + break; + } + case 0x07: + { + // MOD + int idx = dsp_category - 5; + pthread_mutex_lock( &dsp_sync[idx].lock ); + + memcpy( dsp_parms[idx], (const char *)read_buf, 64 ); + updateModObj( read_buf ); + + dsp_sync[idx].value = true; + pthread_cond_signal( &dsp_sync[idx].cond ); + pthread_mutex_unlock( &dsp_sync[idx].lock ); + break; + } + case 0x08: + { + // DELAY + int idx = dsp_category - 5; + pthread_mutex_lock( &dsp_sync[idx].lock ); + + memcpy( dsp_parms[idx], (const char *)read_buf, 64 ); + updateDelayObj( read_buf ); + + dsp_sync[idx].value = true; + pthread_cond_signal( &dsp_sync[idx].cond ); + pthread_mutex_unlock( &dsp_sync[idx].lock ); + break; + } + case 0x09: + { + // REVERB + int idx = dsp_category - 5; + pthread_mutex_lock( &dsp_sync[idx].lock ); + + memcpy( dsp_parms[idx], (const char *)read_buf, 64 ); + updateReverbObj( read_buf ); + + dsp_sync[idx].value = true; + pthread_cond_signal( &dsp_sync[idx].cond ); + pthread_mutex_unlock( &dsp_sync[idx].lock ); + break; + } + case 0x0a: + { + // EXP PEDAL + int idx = dsp_category - 5; + pthread_mutex_lock( &dsp_sync[idx].lock ); + + memcpy( dsp_parms[idx], (const char *)read_buf, 64 ); + + dsp_sync[idx].value = true; + pthread_cond_signal( &dsp_sync[idx].cond ); + pthread_mutex_unlock( &dsp_sync[idx].lock ); + break; + } + default: + // Filler or unknown packet type + break; + } } + else if ( 0==memcmp(read_buf,parms_done,2) ){ + // Parameter dump complete, notify main thread + pthread_mutex_lock( &parm_read_sync.lock ); - return ret; + parm_read_sync.value = true; + pthread_cond_signal( &parm_read_sync.cond ); + pthread_mutex_unlock( &parm_read_sync.lock ); + } + } + + long result = rc; + pthread_exit( (void *)result ); } -int Mustang::setAmp( int ord ) { - if ( tuner_active ) return 0; - int ret, received; - unsigned char scratch[LENGTH]; +int +Mustang::initialize( void ) { + int rc; + + if ( usb_io!=NULL ) return -1; + int init_value = -1; + + rc = libusb_init( NULL ); + if ( rc ) return rc; + + for ( int idx=0; amp_ids[idx].pid != 0; idx++ ) { + if ( ( usb_io = libusb_open_device_with_vid_pid(NULL, FENDER_VID, amp_ids[idx].pid)) != NULL ) { + init_value = amp_ids[idx].init_value; + isV2 = amp_ids[idx].isV2; + break; + } + } + + if ( init_value < 0 ) { + // No amp found + libusb_exit( NULL ); + fprintf( stderr, "S - No Mustang USB device found\n" ); + return -1; + } + + // If kernel driver is active, detach it + if ( libusb_kernel_driver_active( usb_io,0) ) { + // If detach fails, we're hosed... + if ( 0 != (rc = libusb_detach_kernel_driver( usb_io,0)) ) return rc; + } + + // Make it ours + if ( 0 != (rc = libusb_claim_interface( usb_io,0)) ) return rc; + + unsigned char buffer[64]; + int total_count; + + // Phase 1 of amp init + memset( buffer, 0, 64 ); + buffer[1] = 0xc3; + + total_count = 0; + while ( total_count < 64 ) { + int count; + rc = libusb_interrupt_transfer( usb_io, USB_OUT, buffer, 64, &count, USB_TIMEOUT_MS ); + if ( rc && rc!=LIBUSB_ERROR_TIMEOUT ) return rc; + total_count += count; + } + + // Clear reply + total_count = 0; + while ( total_count < 64 ) { + int count; + rc = libusb_interrupt_transfer( usb_io, USB_IN, buffer, 64, &count, USB_TIMEOUT_MS ); + if ( rc && rc!=LIBUSB_ERROR_TIMEOUT ) return rc; + total_count += count; + } + + // Phase 2 of amp init + memset( buffer, 0, 64 ); + buffer[0] = 0x1a; + buffer[1] = init_value; + + total_count = 0; + while ( total_count < 64 ) { + int count; + rc = libusb_interrupt_transfer( usb_io, USB_OUT, buffer, 64, &count, USB_TIMEOUT_MS ); + if ( rc && rc!=LIBUSB_ERROR_TIMEOUT ) return rc; + total_count += count; + } + + // Clear reply + total_count = 0; + while ( total_count < 64 ) { + int count; + rc = libusb_interrupt_transfer( usb_io, USB_IN, buffer, 64, &count, USB_TIMEOUT_MS ); + if ( rc && rc!=LIBUSB_ERROR_TIMEOUT ) return rc; + total_count += count; + } + + return 0; +} + + +int +Mustang::commStart( void ) { + int rc; + unsigned char buffer[64]; + + // Mark as running + want_shutdown = false; + + // Lock the flag + pthread_mutex_lock( &parm_read_sync.lock ); + parm_read_sync.value = false; + + // Start thread + pthread_create( &worker, NULL, threadStarter, this ); + + // Request parm dump + memset( buffer, 0, 64 ); + buffer[0] = 0xff; + buffer[1] = 0xc1; + int total_count = 0; + + while ( total_count < 64 ) { + int count; + rc = libusb_interrupt_transfer( usb_io, USB_OUT, buffer, 64, &count, USB_TIMEOUT_MS ); + if ( rc && rc!=LIBUSB_ERROR_TIMEOUT ) return rc; + total_count += count; + } + + // Block until background thread tells us it's done + while ( !parm_read_sync.value ) pthread_cond_wait( &parm_read_sync.cond, &parm_read_sync.lock ); + pthread_mutex_unlock( &parm_read_sync.lock ); + + return 0; +} + + +int +Mustang::commShutdown( void ) { + pthread_mutex_lock( &shutdown_lock ); + want_shutdown = true; + pthread_mutex_unlock( &shutdown_lock ); + + void *status; + pthread_join( worker, &status ); + + int rc = (long)status; + return rc; +} + + +int +Mustang::deinitialize( void ) { + if ( usb_io==NULL) return 0; + + int rc = libusb_release_interface( usb_io, 0 ); + if ( rc && rc != LIBUSB_ERROR_NO_DEVICE ) return rc; + + if ( (rc = libusb_attach_kernel_driver( usb_io,0)) ) return rc; + + libusb_close( usb_io ); + usb_io = NULL; + + libusb_exit( NULL ); + return 0; +} + + +int +Mustang::tunerMode( int value ) { + int rc, count; + unsigned char buffer[64]; + memset(buffer, 0x00, 64); + + buffer[0] = 0x0a; + buffer[1] = 0x01; + + if ( value > 63 && value <= 127 ) { + // Tuner on + buffer[2] = buffer[3] = buffer[4] = 0x01; + rc = libusb_interrupt_transfer( usb_io, USB_OUT, buffer, 64, &count, USB_TIMEOUT_MS ); + + tuner_active = true; + } + else if ( value >= 0 && value <= 63 ) { + // Tuner off + rc = libusb_interrupt_transfer( usb_io, USB_OUT, buffer, 64, &count, USB_TIMEOUT_MS ); + + libusb_interrupt_transfer( usb_io, USB_IN, buffer, 64, &count, USB_TIMEOUT_MS ); + // sleep( 1 ); + tuner_active = false; + } + + return rc; +} + + +void +Mustang::updateAmpObj( const unsigned char *data ) { + + AmpCC * new_amp = NULL; + + const unsigned char *model = data + MODEL; + + if ( is_type(f57_deluxe_id,model) || + is_type(f57_champ_id,model) || + is_type(f65_deluxe_id,model) || + is_type(f65_princeton_id,model) || + is_type(f65_twin_id,model) || + is_type(s60s_thrift_id,model) ) { + new_amp = new AmpCC( this, model, 0 ); + } + else if ( is_type(f59_bassman_id,model) || + is_type(brit_70s_id,model) ) { + new_amp = new AmpCC1( this, model, 0 ); + } + else if ( is_type(f_supersonic_id,model) ) { + new_amp = new AmpCC2( this, model, 0 ); + } + else if ( is_type(brit_60s_id,model) ) { + new_amp = new AmpCC3( this, model, 0); + } + else if ( is_type(brit_80s_id,model) || + is_type(us_90s_id,model) || + is_type(metal_2k_id,model) || + is_type(brit_watt_id,model) ) { + new_amp = new AmpCC4( this, model, 0 ); + } + else if ( is_type(studio_preamp_id,model) ) { + new_amp = new AmpCC5( this, model, 0 ); + } + else if ( is_type(brit_color_id,model) ) { + new_amp = new AmpCC6( this, model, 0 ); + } + else if ( is_type(f57_twin_id,model) ) { + new_amp = new AmpCC7( this, model, 0 ); + } + else { + fprintf( stderr, "W - Amp id {%x,%x} not supported yet\n", model[0], model[1] ); + } + + if ( new_amp!=NULL ) { + delete curr_amp; + curr_amp = new_amp; + } +} + + +void +Mustang::updateStompObj( const unsigned char *data ) { + + StompCC * new_stomp = NULL; + + const unsigned char *model = data + MODEL; + const unsigned char slot = data[FXSLOT]; + + if ( is_type(overdrive_id,model) ) { + new_stomp = new OverdriveCC( this, model, slot ); + } + else if ( is_type(wah_id,model) || + is_type(touch_wah_id,model) ) { + new_stomp = new WahCC( this, model, slot ); + } + else if ( is_type(fuzz_id,model) ) { + new_stomp = new FuzzCC( this, model, slot ); + } + else if ( is_type(fuzz_twah_id,model) ) { + new_stomp = new FuzzTouchWahCC( this, model, slot ); + } + else if ( is_type(simple_comp_id,model) ) { + new_stomp = new SimpleCompCC( this, model, slot ); + } + else if ( is_type(comp_id,model) ) { + new_stomp = new CompCC( this, model, slot ); + } + else if ( is_type(range_boost_id,model) ) { + new_stomp = new RangerCC( this, model, slot ); + } + else if ( is_type(green_box_id,model) ) { + new_stomp = new GreenBoxCC( this, model, slot ); + } + else if ( is_type(orange_box_id,model) ) { + new_stomp = new OrangeBoxCC( this, model, slot ); + } + else if ( is_type(black_box_id,model) ) { + new_stomp = new BlackBoxCC( this, model, slot ); + } + else if ( is_type(big_fuzz_id,model) ) { + new_stomp = new BigFuzzCC( this, model, slot ); + } + else { + fprintf( stderr, "W - Stomp id {%x,%x} not supported\n", model[0], model[1] ); + } + + if ( new_stomp!=NULL ) { + delete curr_stomp; + curr_stomp = new_stomp; + } +} + + +void +Mustang::updateDelayObj( const unsigned char *data ) { + + DelayCC * new_delay = NULL; - unsigned char *array; + const unsigned char *model = data + MODEL; + const unsigned char slot = data[FXSLOT]; - switch (ord) { + if ( is_type(mono_dly_id,model) ) { + new_delay = new MonoDelayCC( this, model, slot ); + } + else if ( is_type(mono_filter_id,model) || + is_type(st_filter_id,model) ) { + new_delay = new EchoFilterCC( this, model, slot ); + } + else if ( is_type(mtap_dly_id,model) ) { + new_delay = new MultitapDelayCC( this, model, slot ); + } + else if ( is_type(pong_dly_id,model) ) { + new_delay = new PingPongDelayCC( this, model, slot ); + } + else if ( is_type(duck_dly_id,model) ) { + new_delay = new DuckingDelayCC( this, model, slot ); + } + else if ( is_type(reverse_dly_id,model) ) { + new_delay = new ReverseDelayCC( this, model, slot ); + } + else if ( is_type(tape_dly_id,model) ) { + new_delay = new TapeDelayCC( this, model, slot ); + } + else if ( is_type(st_tape_dly_id,model) ) { + new_delay = new StereoTapeDelayCC( this, model, slot ); + } + else { + fprintf( stderr, "W - Delay id {%x,%x} not supported\n", model[0], model[1] ); + } + + if ( new_delay!=NULL ) { + delete curr_delay; + curr_delay = new_delay; + } +} + + +void +Mustang::updateModObj( const unsigned char *data ) { + + ModCC * new_mod = NULL; + + const unsigned char *model = data + MODEL; + const unsigned char slot = data[FXSLOT]; + + if ( is_type(sine_chorus_id,model) || + is_type(tri_chorus_id,model) ) { + new_mod = new ChorusCC( this, model, slot ); + } + else if ( is_type(sine_flange_id,model) || + is_type(tri_flange_id,model) ) { + new_mod = new FlangerCC( this, model, slot ); + } + else if ( is_type(vibratone_id,model) ) { + new_mod = new VibratoneCC( this, model, slot ); + } + else if ( is_type(vint_trem_id,model) || + is_type(sine_trem_id,model) ) { + new_mod = new TremCC( this, model, slot ); + } + else if ( is_type(ring_mod_id,model) ) { + new_mod = new RingModCC( this, model, slot ); + } + else if ( is_type(step_filt_id,model) ) { + new_mod = new StepFilterCC( this, model, slot ); + } + else if ( is_type(phaser_id,model) ) { + new_mod = new PhaserCC( this, model, slot ); + } + else if ( is_type(pitch_shift_id,model) ) { + new_mod = new PitchShifterCC( this, model, slot ); + } + else if ( is_type(m_wah_id,model) || + is_type(m_touch_wah_id,model) ) { + new_mod = new ModWahCC( this, model, slot ); + } + else if ( is_type(dia_pitch_id,model) ) { + new_mod = new DiatonicShiftCC( this, model, slot ); + } + else { + fprintf( stderr, "W - Mod id {%x,%x} not supported\n", model[0], model[1] ); + } + + if ( new_mod!=NULL ) { + delete curr_mod; + curr_mod = new_mod; + } +} + + +void +Mustang::updateReverbObj( const unsigned char *data ) { + + const unsigned char *model = data + MODEL; + const unsigned char slot = data[FXSLOT]; + + delete curr_reverb; + curr_reverb = new ReverbCC( this, model, slot ); +} + + +int +Mustang::effectToggle(int cc, int value) { + if ( tuner_active ) return 0; + + int rc, count; + unsigned char buffer[64]; + + // Translate 23..26 --> 2..5 (current state index) + int state_index = cc - 21; + int state; + if ( value >= 0 && value <= 63 ) state = 1; + else if ( value > 63 && value <= 127 ) state = 0; + + memset(buffer, 0x00, 64); + buffer[0] = 0x19; + buffer[1] = 0xc3; + // Translate DSP to family + buffer[FAMILY] = dsp_parms[state_index][DSP] - 3; + // Invert logic + buffer[ACTIVE_INVERT] = state; + buffer[FXSLOT] = dsp_parms[state_index][FXSLOT]; +#if 0 + for ( int i=0; i<15; i++ ) fprintf( stderr, "%02x ", buffer[i] ); + fprintf( stderr, "\n" ); +#endif + rc = libusb_interrupt_transfer( usb_io, USB_OUT, buffer, 64, &count, USB_TIMEOUT_MS ); + + // Note: Toggle gets three response packets + for (int i=0; i < 3; i++) { + libusb_interrupt_transfer( usb_io, USB_IN, buffer, 64, &count, USB_TIMEOUT_MS ); + } + + return rc; +} + +int +Mustang::setAmp( int ord ) { + if ( tuner_active ) return 0; + + int rc, count; + unsigned char scratch[64]; + + unsigned char *buffer; + + switch (ord) { case 0: - array = amp_none; - break; + buffer = amp_none; + break; case 1: - array = f57_deluxe; - break; + buffer = f57_deluxe; + break; case 2: - array = f59_bassman; - break; + buffer = f59_bassman; + break; case 3: - array = f57_champ; - break; + buffer = f57_champ; + break; case 4: - array = f65_deluxe; - break; + buffer = f65_deluxe; + break; case 5: - array = f65_princeton; - break; + buffer = f65_princeton; + break; case 6: - array = f65_twin; - break; + buffer = f65_twin; + break; case 7: - array = f_supersonic; - break; + buffer = f_supersonic; + break; case 8: - array = brit_60; - break; + buffer = brit_60; + break; case 9: - array = brit_70; - break; + buffer = brit_70; + break; case 10: - array = brit_80; - break; + buffer = brit_80; + break; case 11: - array = us_90; - break; + buffer = us_90; + break; case 12: - array = metal_2k; - break; + buffer = metal_2k; + break; default: - if ( isV2 ) { - switch (ord) { - case 13: - array = studio_preamp; - break; - case 14: - array = f57_twin; - break; - case 15: - array = sixties_thrift; - break; - case 16: - array = brit_watts; - break; - case 17: - array = brit_color; - break; - default: - fprintf( stderr, "W - Amp select %d not supported\n", ord ); - return 0; - } - } - else { + if ( isV2 ) { + switch (ord) { + case 13: + buffer = studio_preamp; + break; + case 14: + buffer = f57_twin; + break; + case 15: + buffer = sixties_thrift; + break; + case 16: + buffer = brit_watts; + break; + case 17: + buffer = brit_color; + break; + default: fprintf( stderr, "W - Amp select %d not supported\n", ord ); return 0; } - } - - // 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[AMP_STATE], array, LENGTH); - updateAmpObj(); - - // Setup USB gain - // memset(scratch, 0x00, LENGTH); - // scratch[0] = 0x1c; - // scratch[1] = 0x03; - // scratch[2] = 0x0d; - // scratch[6] = 0x01; - // scratch[7] = 0x01; - // scratch[16] = 0x80; - - // ret = libusb_interrupt_transfer(amp_hand, 0x01, scratch, 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); - - return ret; -} - -int Mustang::setReverb( int ord ) { - if ( tuner_active ) return 0; - - int ret, received; - unsigned char scratch[LENGTH]; - - unsigned char *array; - - switch (ord) { - case 0: - array = reverb_none; - break; - case 1: - array = small_hall; - break; - case 2: - array = large_hall; - break; - case 3: - array = small_room; - break; - case 4: - array = large_room; - break; - case 5: - array = small_plate; - break; - case 6: - array = large_plate; - break; - case 7: - array = ambient; - break; - case 8: - array = arena; - break; - case 9: - array = spring_63; - break; - case 10: - array = spring_65; - break; - default: - fprintf( stderr, "W - Reverb select %d not supported\n", ord ); + } + else { + fprintf( stderr, "W - Amp select %d not supported\n", ord ); return 0; - } + } + } - array[FXSLOT] = curr_state[REVERB_STATE][FXSLOT]; + // Setup amp personality + rc = libusb_interrupt_transfer( usb_io, USB_OUT, buffer, 64, &count, USB_TIMEOUT_MS ); + libusb_interrupt_transfer( usb_io, USB_IN, scratch, 64, &count, USB_TIMEOUT_MS ); - // Setup amp personality - ret = libusb_interrupt_transfer(amp_hand, 0x01, array, LENGTH, &received, TMOUT); - libusb_interrupt_transfer(amp_hand, 0x81, scratch, LENGTH, &received, TMOUT); + rc = libusb_interrupt_transfer( usb_io, USB_OUT, execute, 64, &count, USB_TIMEOUT_MS ); + libusb_interrupt_transfer( usb_io, USB_IN, scratch, 64, &count, USB_TIMEOUT_MS ); - 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(dsp_parms[AMP_STATE], buffer, 64); +// updateAmpObj("a"); - // Copy to current setting store - memcpy(curr_state[REVERB_STATE], array, LENGTH); - updateReverbObj(); + // Setup USB gain + // memset(scratch, 0x00, 64); + // scratch[0] = 0x1c; + // scratch[1] = 0x03; + // scratch[2] = 0x0d; + // scratch[6] = 0x01; + // scratch[7] = 0x01; + // scratch[16] = 0x80; - return ret; + // rc = libusb_interrupt_transfer( usb_io, USB_OUT, scratch, 64, &count, USB_TIMEOUT_MS ); + // libusb_interrupt_transfer( usb_io, USB_IN, scratch, 64, &count, USB_TIMEOUT_MS ); + + // rc = libusb_interrupt_transfer( usb_io, USB_OUT, execute, 64, &count, USB_TIMEOUT_MS ); + // libusb_interrupt_transfer( usb_io, USB_IN, scratch, 64, &count, USB_TIMEOUT_MS ); + + return rc; } -int Mustang::setDelay( int ord ) { - if ( tuner_active ) return 0; +int +Mustang::setReverb( int ord ) { + if ( tuner_active ) return 0; - int ret, received; - unsigned char scratch[LENGTH]; + int rc, count; + unsigned char scratch[64]; - unsigned char *array; + unsigned char *buffer; - switch (ord) { + switch (ord) { case 0: - array = delay_none; - break; + buffer = reverb_none; + break; case 1: - array = mono_delay; - break; + buffer = small_hall; + break; case 2: - array = mono_echo_filter; - break; + buffer = large_hall; + break; case 3: - array = stereo_echo_filter; - break; + buffer = small_room; + break; case 4: - array = multitap_delay; - break; + buffer = large_room; + break; case 5: - array = ping_pong_delay; - break; + buffer = small_plate; + break; case 6: - array = ducking_delay; - break; + buffer = large_plate; + break; case 7: - array = reverse_delay; - break; + buffer = ambient; + break; case 8: - array = tape_delay; - break; + buffer = arena; + 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; -} - -int Mustang::setMod( int ord ) { - if ( tuner_active ) return 0; - - int ret, received; - unsigned char scratch[LENGTH]; - - unsigned char *array; - - switch (ord) { - case 0: - array = mod_none; - break; - case 1: - array = sine_chorus; - break; - case 2: - array = triangle_chorus; - break; - case 3: - array = sine_flanger; - break; - case 4: - array = triangle_flanger; - break; - case 5: - array = vibratone; - break; - case 6: - array = vintage_tremolo; - break; - case 7: - array = sine_tremolo; - break; - case 8: - array = ring_modulator; - break; - case 9: - array = step_filter; - break; + buffer = spring_63; + break; case 10: - array = phaser; - break; + buffer = spring_65; + break; + default: + fprintf( stderr, "W - Reverb select %d not supported\n", ord ); + return 0; + } + + buffer[FXSLOT] = dsp_parms[REVERB_STATE][FXSLOT]; + + // Setup amp personality + rc = libusb_interrupt_transfer( usb_io, USB_OUT, buffer, 64, &count, USB_TIMEOUT_MS ); + libusb_interrupt_transfer( usb_io, USB_IN, scratch, 64, &count, USB_TIMEOUT_MS ); + + rc = libusb_interrupt_transfer( usb_io, USB_OUT, execute, 64, &count, USB_TIMEOUT_MS ); + libusb_interrupt_transfer( usb_io, USB_IN, scratch, 64, &count, USB_TIMEOUT_MS ); + + // Copy to current setting store + memcpy(dsp_parms[REVERB_STATE], buffer, 64); + // updateReverbObj(); + + return rc; +} + +int +Mustang::setDelay( int ord ) { + if ( tuner_active ) return 0; + + int rc, count; + unsigned char scratch[64]; + + unsigned char *buffer; + + switch (ord) { + case 0: + buffer = delay_none; + break; + case 1: + buffer = mono_delay; + break; + case 2: + buffer = mono_echo_filter; + break; + case 3: + buffer = stereo_echo_filter; + break; + case 4: + buffer = multitap_delay; + break; + case 5: + buffer = ping_pong_delay; + break; + case 6: + buffer = ducking_delay; + break; + case 7: + buffer = reverse_delay; + break; + case 8: + buffer = tape_delay; + break; + case 9: + buffer = stereo_tape_delay; + break; + default: + fprintf( stderr, "W - Delay select %d not supported\n", ord ); + return 0; + } + + buffer[FXSLOT] = dsp_parms[DELAY_STATE][FXSLOT]; + + // Setup amp personality + rc = libusb_interrupt_transfer( usb_io, USB_OUT, buffer, 64, &count, USB_TIMEOUT_MS ); + libusb_interrupt_transfer( usb_io, USB_IN, scratch, 64, &count, USB_TIMEOUT_MS ); + + rc = libusb_interrupt_transfer( usb_io, USB_OUT, execute, 64, &count, USB_TIMEOUT_MS ); + libusb_interrupt_transfer( usb_io, USB_IN, scratch, 64, &count, USB_TIMEOUT_MS ); + + // Copy to current setting store + memcpy(dsp_parms[DELAY_STATE], buffer, 64); +// updateDelayObj(); + + return rc; +} + +int +Mustang::setMod( int ord ) { + if ( tuner_active ) return 0; + + int rc, count; + unsigned char scratch[64]; + + unsigned char *buffer; + + switch (ord) { + case 0: + buffer = mod_none; + break; + case 1: + buffer = sine_chorus; + break; + case 2: + buffer = triangle_chorus; + break; + case 3: + buffer = sine_flanger; + break; + case 4: + buffer = triangle_flanger; + break; + case 5: + buffer = vibratone; + break; + case 6: + buffer = vintage_tremolo; + break; + case 7: + buffer = sine_tremolo; + break; + case 8: + buffer = ring_modulator; + break; + case 9: + buffer = step_filter; + break; + case 10: + buffer = phaser; + break; case 11: - array = pitch_shifter; - break; + buffer = pitch_shifter; + break; default: - if ( isV2 ) { - switch (ord) { - case 12: - array = mod_wah; - break; - case 13: - array = mod_touch_wah; - break; - case 14: - array = diatonic_pitch_shift; - break; - default: - fprintf( stderr, "W - Mod select %d not supported\n", ord ); - return 0; - } - } - else { + if ( isV2 ) { + switch (ord) { + case 12: + buffer = mod_wah; + break; + case 13: + buffer = mod_touch_wah; + break; + case 14: + buffer = diatonic_pitch_shift; + break; + default: fprintf( stderr, "W - Mod select %d not supported\n", ord ); return 0; } - } + } + else { + fprintf( stderr, "W - Mod select %d not supported\n", ord ); + return 0; + } + } - array[FXSLOT] = curr_state[MOD_STATE][FXSLOT]; + buffer[FXSLOT] = dsp_parms[MOD_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); + // Setup amp personality + rc = libusb_interrupt_transfer( usb_io, USB_OUT, buffer, 64, &count, USB_TIMEOUT_MS ); + libusb_interrupt_transfer( usb_io, USB_IN, scratch, 64, &count, USB_TIMEOUT_MS ); - ret = libusb_interrupt_transfer(amp_hand, 0x01, execute, LENGTH, &received, TMOUT); - libusb_interrupt_transfer(amp_hand, 0x81, scratch, LENGTH, &received, TMOUT); + rc = libusb_interrupt_transfer( usb_io, USB_OUT, execute, 64, &count, USB_TIMEOUT_MS ); + libusb_interrupt_transfer( usb_io, USB_IN, scratch, 64, &count, USB_TIMEOUT_MS ); - // Copy to current setting store - memcpy(curr_state[MOD_STATE], array, LENGTH); - updateModObj(); + // Copy to current setting store + memcpy(dsp_parms[MOD_STATE], buffer, 64); + // updateModObj(); - return ret; + return rc; } -int Mustang::setStomp( int ord ) { - if ( tuner_active ) return 0; +int +Mustang::setStomp( int ord ) { + if ( tuner_active ) return 0; - int ret, received; - unsigned char scratch[LENGTH]; + int rc, count; + unsigned char scratch[64]; - unsigned char *array; + unsigned char *buffer; - switch (ord) { + switch (ord) { case 0: - array = stomp_none; - break; + buffer = stomp_none; + break; case 1: - array = overdrive; - break; + buffer = overdrive; + break; case 2: - array = wah; - break; + buffer = wah; + break; case 3: - array = touch_wah; - break; + buffer = touch_wah; + break; case 4: - array = fuzz; - break; + buffer = fuzz; + break; case 5: - if ( isV2 ) { - fprintf( stderr, "W - Stomp select %d not supported\n", ord ); - return 0; - } - else { - array = fuzz_touch_wah; - } - break; + if ( isV2 ) { + fprintf( stderr, "W - Stomp select %d not supported\n", ord ); + return 0; + } + else { + buffer = fuzz_touch_wah; + } + break; case 6: - array = simple_comp; - break; + buffer = simple_comp; + break; case 7: - array = compressor; - break; + buffer = compressor; + break; default: - if ( isV2 ) { - switch (ord) { - case 8: - array = ranger_boost; - break; - case 9: - array = green_box; - break; - case 10: - array = orange_box; - break; - case 11: - array = black_box; - break; - case 12: - array = big_fuzz; - break; - default: - fprintf( stderr, "W - Stomp select %d not supported\n", ord ); - return 0; - } - } - else { + if ( isV2 ) { + switch (ord) { + case 8: + buffer = ranger_boost; + break; + case 9: + buffer = green_box; + break; + case 10: + buffer = orange_box; + break; + case 11: + buffer = black_box; + break; + case 12: + buffer = big_fuzz; + break; + default: fprintf( stderr, "W - Stomp select %d not supported\n", ord ); return 0; } - } + } + else { + fprintf( stderr, "W - Stomp select %d not supported\n", ord ); + return 0; + } + } - array[FXSLOT] = curr_state[STOMP_STATE][FXSLOT]; + buffer[FXSLOT] = dsp_parms[STOMP_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); + // Setup amp personality + rc = libusb_interrupt_transfer( usb_io, USB_OUT, buffer, 64, &count, USB_TIMEOUT_MS ); + libusb_interrupt_transfer( usb_io, USB_IN, scratch, 64, &count, USB_TIMEOUT_MS ); - ret = libusb_interrupt_transfer(amp_hand, 0x01, execute, LENGTH, &received, TMOUT); - libusb_interrupt_transfer(amp_hand, 0x81, scratch, LENGTH, &received, TMOUT); + rc = libusb_interrupt_transfer( usb_io, USB_OUT, execute, 64, &count, USB_TIMEOUT_MS ); + libusb_interrupt_transfer( usb_io, USB_IN, scratch, 64, &count, USB_TIMEOUT_MS ); - // Copy to current setting store - memcpy(curr_state[STOMP_STATE], array, LENGTH); - updateStompObj(); + // Copy to current setting store + memcpy(dsp_parms[STOMP_STATE], buffer, 64); +// updateStompObj(); - return ret; + return rc; } -int Mustang::save_on_amp(char *name, int slot) -{ - if ( tuner_active ) return 0; - int ret, received; - unsigned char array[LENGTH]; +int +Mustang::continuous_control( const Mustang::Cmd & cmd ) { + if ( tuner_active ) return 0; - memset(array, 0x00, LENGTH); - array[0] = 0x1c; - array[1] = 0x01; - array[2] = 0x03; - array[SAVE_SLOT] = slot; - array[6] = 0x01; - array[7] = 0x01; - - if(strlen(name) > 31) - name[31] = 0x00; - - for(unsigned int i = 16, j = 0; name[j] != 0x00; i++,j++) - array[i] = name[j]; - - ret = libusb_interrupt_transfer(amp_hand, 0x01, array, LENGTH, &received, TMOUT); - libusb_interrupt_transfer(amp_hand, 0x81, array, LENGTH, &received, TMOUT); - - load_memory_bank(slot); - - return ret; -} - -int Mustang::continuous_control( const Mustang::Cmd & cmd ) { - if ( tuner_active ) return 0; - - int ret, received; - unsigned char array[LENGTH]; + int rc, count; + unsigned char buffer[64]; - memset(array, 0x00, LENGTH); - array[0] = 0x05; - array[1] = 0xc3; - array[2] = cmd.parm2; - array[3] = curr_state[cmd.state_index][MODEL]; + memset(buffer, 0x00, 64); + buffer[0] = 0x05; + buffer[1] = 0xc3; + buffer[2] = cmd.parm2; + buffer[3] = dsp_parms[cmd.state_index][MODEL]; - // target parameter - array[5] = cmd.parm5; - array[6] = cmd.parm6; - array[7] = cmd.parm7; + // target parameter + buffer[5] = cmd.parm5; + buffer[6] = cmd.parm6; + buffer[7] = cmd.parm7; - // Scale and clamp to valid index range - int index = (int) ceil( (double)cmd.value * magic_scale_factor ); - if ( index > magic_max ) index = magic_max; + // Scale and clamp to valid index range + int index = (int) ceil( (double)cmd.value * magic_scale_factor ); + if ( index > magic_max ) index = magic_max; - unsigned short eff_value = magic_values[index]; + unsigned short eff_value = magic_values[index]; - array[9] = eff_value & 0xff; - array[10] = (eff_value >> 8) & 0xff; + buffer[9] = eff_value & 0xff; + buffer[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); + // Send command and flush reply + rc = libusb_interrupt_transfer( usb_io, USB_OUT, buffer, 64, &count, USB_TIMEOUT_MS ); + libusb_interrupt_transfer( usb_io, USB_IN, buffer, 64, &count, USB_TIMEOUT_MS ); - return ret; + return rc; } -int Mustang::discrete_control( const Mustang::Cmd & cmd ) { - if ( tuner_active ) return 0; +int +Mustang::discrete_control( const Mustang::Cmd & cmd ) { + if ( tuner_active ) return 0; - int ret, received; - unsigned char array[LENGTH]; + int rc, count; + unsigned char buffer[64]; - memset(array, 0x00, LENGTH); - array[0] = 0x05; - array[1] = 0xc3; - array[2] = cmd.parm2; - array[3] = curr_state[cmd.state_index][MODEL]; + memset(buffer, 0x00, 64); + buffer[0] = 0x05; + buffer[1] = 0xc3; + buffer[2] = cmd.parm2; + buffer[3] = dsp_parms[cmd.state_index][MODEL]; - array[5] = cmd.parm5; - array[6] = cmd.parm6; - array[7] = cmd.parm7; + buffer[5] = cmd.parm5; + buffer[6] = cmd.parm6; + buffer[7] = cmd.parm7; - // Discrete value - array[9] = cmd.value; + // Discrete value + buffer[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); + // Send command and flush reply + rc = libusb_interrupt_transfer( usb_io, USB_OUT, buffer, 64, &count, USB_TIMEOUT_MS ); + libusb_interrupt_transfer( usb_io, USB_IN, buffer, 64, &count, USB_TIMEOUT_MS ); - return ret; + return rc; } -int Mustang::load_memory_bank( int slot ) -{ - if ( tuner_active ) return 0; +int +Mustang::patchChange( int patch ) { + if ( tuner_active ) return 0; - int ret, received; - unsigned char array[LENGTH], data[7][LENGTH]; + int rc, count; + unsigned char buffer[64], data[7][64]; - memset(array, 0x00, LENGTH); - array[0] = 0x1c; - array[1] = 0x01; - array[2] = 0x01; - array[SAVE_SLOT] = slot; - array[6] = 0x01; + memset(buffer, 0x00, 64); + buffer[0] = 0x1c; + buffer[1] = 0x01; + buffer[2] = 0x01; + buffer[PATCH_SLOT] = patch; + buffer[6] = 0x01; - ret = libusb_interrupt_transfer(amp_hand, 0x01, array, LENGTH, &received, TMOUT); + rc = libusb_interrupt_transfer( usb_io, USB_OUT, buffer, 64, &count, USB_TIMEOUT_MS ); - // Mustang III has nine responses - for(int i=0; i < 9; i++) { - libusb_interrupt_transfer(amp_hand, 0x81, array, LENGTH, &received, TMOUT); - int dsp = array[2]; - if ( dsp >= 4 && dsp <= 9 ) - memcpy(curr_state[dsp - 4], array, LENGTH); - } - updateAmpObj(); - updateReverbObj(); - updateDelayObj(); - updateModObj(); - updateStompObj(); + // Mustang III has nine responses + for(int i=0; i < 9; i++) { + libusb_interrupt_transfer( usb_io, USB_IN, buffer, 64, &count, USB_TIMEOUT_MS ); + int dsp = buffer[2]; + if ( dsp >= 4 && dsp <= 9 ) + memcpy(dsp_parms[dsp - 4], buffer, 64); + } +// updateAmpObj("a"); +// updateReverbObj(); +// updateDelayObj(); +// updateModObj(); +// updateStompObj(); - return ret; -} - -int Mustang::set_effect(struct fx_pedal_settings value) -{ - int ret, received; // variables used when sending - unsigned char slot; // where to put the effect - unsigned char temp[LENGTH], array[LENGTH] = { - 0x1c, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - - // clear effect on previous DSP before setting a new one - int k=0; - for (int i = 0; i < 4; i++) - { - if (prev_array[i][FXSLOT] == value.fx_slot || prev_array[i][FXSLOT] == (value.fx_slot+4)) - { - memcpy(array, prev_array[i], LENGTH); - prev_array[i][FXSLOT] = 0xff; - k++; - break; - } - } - array[EFFECT] = 0x00; - array[KNOB1] = 0x00; - array[KNOB2] = 0x00; - array[KNOB3] = 0x00; - array[KNOB4] = 0x00; - array[KNOB5] = 0x00; - array[KNOB6] = 0x00; - ret = libusb_interrupt_transfer(amp_hand, 0x01, array, LENGTH, &received, TMOUT); - libusb_interrupt_transfer(amp_hand, 0x81, temp, LENGTH, &received, TMOUT); - ret = libusb_interrupt_transfer(amp_hand, 0x01, execute, LENGTH, &received, TMOUT); - libusb_interrupt_transfer(amp_hand, 0x81, temp, LENGTH, &received, TMOUT); - - if(value.effect_num == EMPTY) - return ret; - - if(value.put_post_amp) // put effect in a slot after amplifier - slot = value.fx_slot + 4; - else - slot = value.fx_slot; - - // fill the form with data - array[FXSLOT] = slot; - array[KNOB1] = value.knob1; - array[KNOB2] = value.knob2; - array[KNOB3] = value.knob3; - array[KNOB4] = value.knob4; - array[KNOB5] = value.knob5; - // some effects have more knobs - if (value.effect_num == MONO_ECHO_FILTER || - value.effect_num == STEREO_ECHO_FILTER || - value.effect_num == TAPE_DELAY || - value.effect_num == STEREO_TAPE_DELAY) - { - array[KNOB6] = value.knob6; - } - - // fill the form with missing data - switch (value.effect_num) { - case OVERDRIVE: - array[DSP] = 0x06; - array[EFFECT] = 0x3c; - break; - - case WAH: - array[DSP] = 0x06; - array[EFFECT] = 0x49; - array[19] = 0x01; - break; - - case TOUCH_WAH: - array[DSP] = 0x06; - array[EFFECT] = 0x4a; - array[19] = 0x01; - break; - - case FUZZ: - array[DSP] = 0x06; - array[EFFECT] = 0x1a; - break; - - case FUZZ_TOUCH_WAH: - array[DSP] = 0x06; - array[EFFECT] = 0x1c; - break; - - case SIMPLE_COMP: - array[DSP] = 0x06; - array[EFFECT] = 0x88; - array[19] = 0x08; - if(array[KNOB1] > 0x03) - { - array[KNOB1] = 0x03; - } - array[KNOB2] = 0x00; - array[KNOB3] = 0x00; - array[KNOB4] = 0x00; - array[KNOB5] = 0x00; - break; - - case COMPRESSOR: - array[DSP] = 0x06; - array[EFFECT] = 0x07; - break; - - case SINE_CHORUS: - array[DSP] = 0x07; - array[EFFECT] = 0x12; - array[19] = 0x01; - array[20] = 0x01; - break; - - case TRIANGLE_CHORUS: - array[DSP] = 0x07; - array[EFFECT] = 0x13; - array[19] = 0x01; - array[20] = 0x01; - break; - - case SINE_FLANGER: - array[DSP] = 0x07; - array[EFFECT] = 0x18; - array[19] = 0x01; - array[20] = 0x01; - break; - - case TRIANGLE_FLANGER: - array[DSP] = 0x07; - array[EFFECT] = 0x19; - array[19] = 0x01; - array[20] = 0x01; - break; - - case VIBRATONE: - array[DSP] = 0x07; - array[EFFECT] = 0x2d; - array[19] = 0x01; - array[20] = 0x01; - break; - - case VINTAGE_TREMOLO: - array[DSP] = 0x07; - array[EFFECT] = 0x40; - array[19] = 0x01; - array[20] = 0x01; - break; - - case SINE_TREMOLO: - array[DSP] = 0x07; - array[EFFECT] = 0x41; - array[19] = 0x01; - array[20] = 0x01; - break; - - case RING_MODULATOR: - array[DSP] = 0x07; - array[EFFECT] = 0x22; - array[19] = 0x01; - if(array[KNOB4] > 0x01) - { - array[KNOB4] = 0x01; - } - break; - - case STEP_FILTER: - array[DSP] = 0x07; - array[EFFECT] = 0x29; - array[19] = 0x01; - array[20] = 0x01; - break; - - case PHASER: - array[DSP] = 0x07; - array[EFFECT] = 0x4f; - array[19] = 0x01; - array[20] = 0x01; - if(array[KNOB5] > 0x01) - { - array[KNOB5] = 0x01; - } - break; - - case PITCH_SHIFTER: - array[DSP] = 0x07; - array[EFFECT] = 0x1f; - array[19] = 0x01; - break; - - case MONO_DELAY: - array[DSP] = 0x08; - array[EFFECT] = 0x16; - array[19] = 0x02; - array[20] = 0x01; - break; - - case MONO_ECHO_FILTER: - array[DSP] = 0x08; - array[EFFECT] = 0x43; - array[19] = 0x02; - array[20] = 0x01; - break; - - case STEREO_ECHO_FILTER: - array[DSP] = 0x08; - array[EFFECT] = 0x48; - array[19] = 0x02; - array[20] = 0x01; - break; - - case MULTITAP_DELAY: - array[DSP] = 0x08; - array[EFFECT] = 0x44; - array[19] = 0x02; - array[20] = 0x01; - if(array[KNOB5] > 0x03) - { - array[KNOB5] = 0x03; - } - break; - - case PING_PONG_DELAY: - array[DSP] = 0x08; - array[EFFECT] = 0x45; - array[19] = 0x02; - array[20] = 0x01; - break; - - case DUCKING_DELAY: - array[DSP] = 0x08; - array[EFFECT] = 0x15; - array[19] = 0x02; - array[20] = 0x01; - break; - - case REVERSE_DELAY: - array[DSP] = 0x08; - array[EFFECT] = 0x46; - array[19] = 0x02; - array[20] = 0x01; - break; - - case TAPE_DELAY: - array[DSP] = 0x08; - array[EFFECT] = 0x2b; - array[19] = 0x02; - array[20] = 0x01; - break; - - case STEREO_TAPE_DELAY: - array[DSP] = 0x08; - array[EFFECT] = 0x2a; - array[19] = 0x02; - array[20] = 0x01; - break; - - case SMALL_HALL_REVERB: - array[DSP] = 0x09; - array[EFFECT] = 0x24; - break; - - case LARGE_HALL_REVERB: - array[DSP] = 0x09; - array[EFFECT] = 0x3a; - break; - - case SMALL_ROOM_REVERB: - array[DSP] = 0x09; - array[EFFECT] = 0x26; - break; - - case LARGE_ROOM_REVERB: - array[DSP] = 0x09; - array[EFFECT] = 0x3b; - break; - - case SMALL_PLATE_REVERB: - array[DSP] = 0x09; - array[EFFECT] = 0x4e; - break; - - case LARGE_PLATE_REVERB: - array[DSP] = 0x09; - array[EFFECT] = 0x4b; - break; - - case AMBIENT_REVERB: - array[DSP] = 0x09; - array[EFFECT] = 0x4c; - break; - - case ARENA_REVERB: - array[DSP] = 0x09; - array[EFFECT] = 0x4d; - break; - - case FENDER_63_SPRING_REVERB: - array[DSP] = 0x09; - array[EFFECT] = 0x21; - break; - - case FENDER_65_SPRING_REVERB: - array[DSP] = 0x09; - array[EFFECT] = 0x0b; - break; - } - - // send packet to the amp - ret = libusb_interrupt_transfer(amp_hand, 0x01, array, LENGTH, &received, TMOUT); - libusb_interrupt_transfer(amp_hand, 0x81, temp, LENGTH, &received, TMOUT); - - ret = libusb_interrupt_transfer(amp_hand, 0x01, execute, LENGTH, &received, TMOUT); - libusb_interrupt_transfer(amp_hand, 0x81, temp, LENGTH, &received, TMOUT); - - // save current settings - memcpy(prev_array[array[DSP]-6], array, LENGTH); - - return ret; -} - -int Mustang::save_effects(int slot, char name[24], int number_of_effects, struct fx_pedal_settings effects[2]) -{ - int ret, received; - unsigned char fxknob, repeat; - unsigned char temp[LENGTH], array[LENGTH] = { - 0x1c, 0x01, 0x04, 0x00, 0x00, 0x00, 0x01, 0x01, - 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, 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, 0x00, 0x00 - }; - execute[2]=0x00; // why this must be here? - - if(number_of_effects > 2) - repeat = 1; - else - repeat = number_of_effects; - - for(int i = 0; i < repeat; i++) - if(effects[i].effect_num < SINE_CHORUS) - return -1; - - if(effects[0].effect_num>=SINE_CHORUS && effects[0].effect_num<=PITCH_SHIFTER) - { - fxknob = 0x01; - repeat = 1; //just to be sure - } - else - fxknob = 0x02; - array[FXKNOB] = fxknob; - - array[SAVE_SLOT] = slot; - - // set and send the name - if(name[24] != 0x00) - name[24] = 0x00; - for(int i = 0, j = 16; name[i] != 0x00; i++, j++) - array[j] = name[i]; - ret = libusb_interrupt_transfer(amp_hand, 0x01, array, LENGTH, &received, TMOUT); - libusb_interrupt_transfer(amp_hand, 0x81, temp, LENGTH, &received, TMOUT); - - array[1] = 0x03; - array[6] = 0x00; - memset(array+16, 0x00, LENGTH-16); - for(int i = 0; i < repeat; i++) - { - array[19] = 0x00; - array[20] = 0x08; - array[21] = 0x01; - array[KNOB6] = 0x00; - - if(effects[i].put_post_amp) - array[FXSLOT] = effects[i].fx_slot+4; - else - array[FXSLOT] = effects[i].fx_slot; - array[KNOB1] = effects[i].knob1; - array[KNOB2] = effects[i].knob2; - array[KNOB3] = effects[i].knob3; - array[KNOB4] = effects[i].knob4; - array[KNOB5] = effects[i].knob5; - // some effects have more knobs - if (effects[i].effect_num == MONO_ECHO_FILTER || - effects[i].effect_num == STEREO_ECHO_FILTER || - effects[i].effect_num == TAPE_DELAY || - effects[i].effect_num == STEREO_TAPE_DELAY) - { - array[KNOB6] = effects[i].knob6; - } - - // fill the form with missing data - switch (effects[i].effect_num) { - case SINE_CHORUS: - array[DSP] = 0x07; - array[EFFECT] = 0x12; - array[19] = 0x01; - array[20] = 0x01; - break; - - case TRIANGLE_CHORUS: - array[DSP] = 0x07; - array[EFFECT] = 0x13; - array[19] = 0x01; - array[20] = 0x01; - break; - - case SINE_FLANGER: - array[DSP] = 0x07; - array[EFFECT] = 0x18; - array[19] = 0x01; - array[20] = 0x01; - break; - - case TRIANGLE_FLANGER: - array[DSP] = 0x07; - array[EFFECT] = 0x19; - array[19] = 0x01; - array[20] = 0x01; - break; - - case VIBRATONE: - array[DSP] = 0x07; - array[EFFECT] = 0x2d; - array[19] = 0x01; - array[20] = 0x01; - break; - - case VINTAGE_TREMOLO: - array[DSP] = 0x07; - array[EFFECT] = 0x40; - array[19] = 0x01; - array[20] = 0x01; - break; - - case SINE_TREMOLO: - array[DSP] = 0x07; - array[EFFECT] = 0x41; - array[19] = 0x01; - array[20] = 0x01; - break; - - case RING_MODULATOR: - array[DSP] = 0x07; - array[EFFECT] = 0x22; - array[19] = 0x01; - if(array[KNOB4] > 0x01) - array[KNOB4] = 0x01; - break; - - case STEP_FILTER: - array[DSP] = 0x07; - array[EFFECT] = 0x29; - array[19] = 0x01; - array[20] = 0x01; - break; - - case PHASER: - array[DSP] = 0x07; - array[EFFECT] = 0x4f; - array[19] = 0x01; - array[20] = 0x01; - if(array[KNOB5] > 0x01) - array[KNOB5] = 0x01; - break; - - case PITCH_SHIFTER: - array[DSP] = 0x07; - array[EFFECT] = 0x1f; - array[19] = 0x01; - break; - - case MONO_DELAY: - array[DSP] = 0x08; - array[EFFECT] = 0x16; - array[19] = 0x02; - array[20] = 0x01; - break; - - case MONO_ECHO_FILTER: - array[DSP] = 0x08; - array[EFFECT] = 0x43; - array[19] = 0x02; - array[20] = 0x01; - break; - - case STEREO_ECHO_FILTER: - array[DSP] = 0x08; - array[EFFECT] = 0x48; - array[19] = 0x02; - array[20] = 0x01; - break; - - case MULTITAP_DELAY: - array[DSP] = 0x08; - array[EFFECT] = 0x44; - array[19] = 0x02; - array[20] = 0x01; - break; - - case PING_PONG_DELAY: - array[DSP] = 0x08; - array[EFFECT] = 0x45; - array[19] = 0x02; - array[20] = 0x01; - break; - - case DUCKING_DELAY: - array[DSP] = 0x08; - array[EFFECT] = 0x15; - array[19] = 0x02; - array[20] = 0x01; - break; - - case REVERSE_DELAY: - array[DSP] = 0x08; - array[EFFECT] = 0x46; - array[19] = 0x02; - array[20] = 0x01; - break; - - case TAPE_DELAY: - array[DSP] = 0x08; - array[EFFECT] = 0x2b; - array[19] = 0x02; - array[20] = 0x01; - break; - - case STEREO_TAPE_DELAY: - array[DSP] = 0x08; - array[EFFECT] = 0x2a; - array[19] = 0x02; - array[20] = 0x01; - break; - - case SMALL_HALL_REVERB: - array[DSP] = 0x09; - array[EFFECT] = 0x24; - break; - - case LARGE_HALL_REVERB: - array[DSP] = 0x09; - array[EFFECT] = 0x3a; - break; - - case SMALL_ROOM_REVERB: - array[DSP] = 0x09; - array[EFFECT] = 0x26; - break; - - case LARGE_ROOM_REVERB: - array[DSP] = 0x09; - array[EFFECT] = 0x3b; - break; - - case SMALL_PLATE_REVERB: - array[DSP] = 0x09; - array[EFFECT] = 0x4e; - break; - - case LARGE_PLATE_REVERB: - array[DSP] = 0x09; - array[EFFECT] = 0x4b; - break; - - case AMBIENT_REVERB: - array[DSP] = 0x09; - array[EFFECT] = 0x4c; - break; - - case ARENA_REVERB: - array[DSP] = 0x09; - array[EFFECT] = 0x4d; - break; - - case FENDER_63_SPRING_REVERB: - array[DSP] = 0x09; - array[EFFECT] = 0x21; - break; - - case FENDER_65_SPRING_REVERB: - array[DSP] = 0x09; - array[EFFECT] = 0x0b; - break; - } - // send packet - ret = libusb_interrupt_transfer(amp_hand, 0x01, array, LENGTH, &received, TMOUT); - libusb_interrupt_transfer(amp_hand, 0x81, temp, LENGTH, &received, TMOUT); - } - - execute[FXKNOB] = fxknob; - ret = libusb_interrupt_transfer(amp_hand, 0x01, execute, LENGTH, &received, TMOUT); - libusb_interrupt_transfer(amp_hand, 0x81, temp, LENGTH, &received, TMOUT); - execute[FXKNOB] = 0x00; - - return 0; + return rc; } diff --git a/mustang.h b/mustang.h index b62a365..fb88484 100644 --- a/mustang.h +++ b/mustang.h @@ -1,185 +1,18 @@ // -*-c++-*- -#ifndef MUSTANG_H -#define MUSTANG_H +#ifndef MUSTANG2_H +#define MUSTANG2_H -#include -#include -#include +#include +#include #include -#include "effects_enum.h" -#include "data_structs.h" +#include +#include "constants.h" -// amp's VID and PID -#define USB_VID 0x1ed8 -#define OLD_USB_PID 0x0004 //Mustang I and II -#define NEW_USB_PID 0x0005 //Mustang III, IV and V -#define V2_USB_PID 0x0014 // Mustang II (and I? !) V2 -#define MINI_USB_PID 0x0010 //Mustang Mini -#define FLOOR_USB_PID 0x0012 //Mustang Floor -#define BRONCO40_USB_PID 0x0a //BRONCO 40 -#define V2_III_PID 0x16 // Mustang III v2 -#define V2_IV_PID 0x17 // Mustang IV v2 (?) - -// amp's VID and PID while in update mode -#define USB_UPDATE_VID 0x1ed8 -#define OLD_USB_UPDATE_PID 0x0006 //Mustang I and II -#define NEW_USB_UPDATE_PID 0x0007 //Mustang III, IV, V -#define MINI_USB_UPDATE_PID 0x0011 //Mustang Mini -#define FLOOR_USB_UPDATE_PID 0x0013 //Mustang Floor -// #define BRONCO40_USB_PID 0x00a //BRONCO 40 - - -// for USB communication -#define TMOUT 500 -#define LENGTH 64 - - -// effect array fields -#define DSP 2 -#define EFFECT 16 -#define FXSLOT 18 -#define KNOB1 32 -#define KNOB2 33 -#define KNOB3 34 -#define KNOB4 35 -#define KNOB5 36 -#define KNOB6 37 - -// amp array fields -#define AMPLIFIER 16 -#define VOLUME 32 -#define GAIN 33 -#define TREBLE 36 -#define MIDDLE 37 -#define BASS 38 -#define CABINET 49 -#define NOISE_GATE 47 -#define THRESHOLD 48 -#define MASTER_VOL 35 -#define GAIN2 34 -#define PRESENCE 39 -#define DEPTH 41 -#define BIAS 42 -#define SAG 51 -#define BRIGHTNESS 52 - -// save fields -#define SAVE_SLOT 4 -#define FXKNOB 3 - -// direct control fields -#define FAMILY 2 -#define ACTIVE_INVERT 3 - -// Offset to current device model for any state structure -#define MODEL 16 -#define MODELX 17 - -// Index into current state structure -#define PRESET_NAME 0 -#define AMP_STATE 1 -#define STOMP_STATE 2 -#define MOD_STATE 3 -#define DELAY_STATE 4 -#define REVERB_STATE 5 -#define EXP_STATE 6 - -// DSP Category -#define AMP_DSP 5 -#define STOMP_DSP 6 -#define MOD_DSP 7 -#define DELAY_DSP 8 -#define REVERB_DSP 9 - -// DSP Family (used for direct parm set) - Effectively DSP - 3 -#define STOMP_FAM 3 -#define MOD_FAM 4 -#define DELAY_FAM 5 -#define REVERB_FAM 6 - -// Amp model id values -#define F57_DELUXE_ID 0x67 -#define F59_BASSMAN_ID 0x64 -#define F57_CHAMP_ID 0x7c -#define F65_DELUXE_ID 0x53 -#define F65_PRINCETON_ID 0x6a -#define F65_TWIN_ID 0x75 -#define F_SUPERSONIC_ID 0x72 -#define BRIT_60S_ID 0x61 -#define BRIT_70S_ID 0x79 -#define BRIT_80S_ID 0x5e -#define US_90S_ID 0x5d -#define METAL_2K_ID 0x6d - -// v2 amp only -#define STUDIO_PREAMP_ID 0xf1 -#define F57_TWIN_ID 0xf6 -#define S60S_THRIFT_ID 0xf9 -#define BRIT_WATT_ID 0xff -#define BRIT_COLOR_ID 0xfc - -// Reverb model id values -#define SM_HALL_ID 0x24 -#define LG_HALL_ID 0x3a -#define SM_ROOM_ID 0x26 -#define LG_ROOM_ID 0x3b -#define SM_PLATE_ID 0x4e -#define LG_PLATE_ID 0x4b -#define AMBIENT_ID 0x4c -#define ARENA_ID 0x4d -#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 - -// Mod model id values -#define SINE_CHORUS_ID 0x12 -#define TRI_CHORUS_ID 0x13 -#define SINE_FLANGE_ID 0x18 -#define TRI_FLANGE_ID 0x19 -#define VIBRATONE_ID 0x2d -#define VINT_TREM_ID 0x40 -#define SINE_TREM_ID 0x41 -#define RING_MOD_ID 0x22 -#define STEP_FILT_ID 0x29 -#define PHASER_ID 0x4f -// Note: Diatonic shifter also uses this as model byte and -// is differentiated by 0x10 in the following 'extra' model byte. -#define PITCH_SHIFT_ID 0x1f - -// v2 mod only -#define M_WAH_ID 0xf4 -#define M_TOUCH_WAH_ID 0xf5 - -// Stomp model id values -#define OVERDRIVE_ID 0x3c -#define WAH_ID 0x49 -#define TOUCH_WAH_ID 0x4a -#define FUZZ_ID 0x1a - -// This is not present in v2: -#define FUZZ_TWAH_ID 0x1c - -#define SIMPLE_COMP_ID 0x88 -#define COMP_ID 0x07 - -// v2 stomp only -#define RANGE_BOOST_ID 0x03 -#define GREEN_BOX_ID 0xba -#define ORANGE_BOX_ID 0x10 -#define BLACK_BOX_ID 0x11 -#define BIG_FUZZ_ID 0x0f +#define USB_IN 0x81 +#define USB_OUT 0x01 +#define USB_TIMEOUT_MS 500 class AmpCC; class ReverbCC; @@ -188,108 +21,134 @@ class ModCC; class StompCC; class Mustang { - friend class AmpCC; - friend class ReverbCC; - friend class DelayCC; - friend class ModCC; - friend class StompCC; + friend class AmpCC; + friend class ReverbCC; + friend class DelayCC; + friend class ModCC; + friend class StompCC; -public: - Mustang(); - ~Mustang(); - int start_amp(void); // initialize communication - int stop_amp(void); // terminate communication - int set_effect(struct fx_pedal_settings); + char preset_names[100][33]; + unsigned curr_preset_idx; + + unsigned char dsp_parms[6][64]; - int setAmp( int ord ); - int setReverb( int ord ); - int setDelay( int ord ); - int setMod( int ord ); - int setStomp( int ord ); + unsigned char curr_model[5][2]; - int tunerMode( int value ); - - int save_on_amp(char *, int); - int load_memory_bank(int); - int save_effects(int , char *, int , struct fx_pedal_settings *); + unsigned char execute[64]; - int effect_toggle(int cc, int value); + static const unsigned char state_prefix[]; + static const unsigned char parms_done[]; - AmpCC * getAmp( void ) { return curr_amp;} - ReverbCC * getReverb( void ) { return curr_reverb;} - DelayCC * getDelay( void ) { return curr_delay;} - ModCC * getMod( void ) { return curr_mod;} - StompCC * getStomp( void ) { return curr_stomp;} + static const unsigned char tuner_ack[]; + static const unsigned char tuner_prefix[]; - struct Cmd { - int state_index; - int parm2; - int parm5; - int parm6; - int parm7; - int value; - }; + static const unsigned char select_ack[]; + static const unsigned char cc_ack[]; + + libusb_device_handle *usb_io; + + pthread_t worker; + + pthread_mutex_t data_lock = PTHREAD_MUTEX_INITIALIZER; + + pthread_mutex_t shutdown_lock = PTHREAD_MUTEX_INITIALIZER; + bool want_shutdown; + + template + class Condition { + public: + pthread_mutex_t lock; + pthread_cond_t cond; + T value; + Condition( void ) { + pthread_mutex_init( &(lock), NULL); + pthread_cond_init( &(cond), NULL); + } + }; + + // Manage access to each DSP block + Condition dsp_sync[5]; + + Condition preset_names_sync; + + // Synchronize init on end of initial parm dump + Condition parm_read_sync; + + struct usb_id { + // product id + int pid; + // magic value for init packet + int init_value; + // v2? + bool isV2; + }; + + // For device probe + static const usb_id amp_ids[]; + bool isV2; + + static void *threadStarter( void * ); + void handleInput( void ); + + bool tuner_active; + + AmpCC * curr_amp; + ReverbCC * curr_reverb; + DelayCC * curr_delay; + ModCC * curr_mod; + StompCC * curr_stomp; + +public: + struct Cmd { + int state_index; + int parm2; + int parm5; + int parm6; + int parm7; + int value; + }; private: + int continuous_control( const Mustang::Cmd & cmd ); + int discrete_control( const Mustang::Cmd & cmd ); + + void updateAmpObj( const unsigned char *data ); + void updateStompObj( const unsigned char *data ); + void updateReverbObj( const unsigned char *data ); + void updateDelayObj( const unsigned char *data ); + void updateModObj( const unsigned char *data ); - struct usb_id { - // product id - int pid; - // magic value for init packet - int init_value; - // v2? - bool isV2; - }; + inline bool is_type(const unsigned char *a, const unsigned char *b) { + return ( 0==memcmp(a,b,2) ); + } - // For device probe - static usb_id ids[]; +public: + Mustang( void ); - libusb_device_handle *amp_hand; // handle for USB communication - unsigned char execute[LENGTH]; // "apply" command sent after each instruction + int initialize( void ); + int deinitialize( void ); + + int commStart( void ); + int commShutdown( void ); - bool isV2; - - // Current state of effects. Read from amp initially and maintained - // as we change it. Major index is DSP# - 6, where: - // - // 0 : Stomp - // 1 : Modulation - // 2 : Delay - // 3 : Reverb - // - unsigned char prev_array[4][LENGTH]; // array used to clear the effect + int setAmp( int ord ); + int setReverb( int ord ); + int setDelay( int ord ); + int setMod( int ord ); + int setStomp( int ord ); + int tunerMode( int value ); - // Current state of amp. - // - // 0 : Preset Name - // 1 : Amp - // 2 : Stomp - // 3 : Mod - // 4 : Delay - // 5 : Reverb - // 6 : Expression Pedal - // - unsigned char curr_state[7][LENGTH]; + int patchChange( int ); - bool tuner_active; + int effectToggle( int cc, int value ); - AmpCC * curr_amp; - ReverbCC * curr_reverb; - DelayCC * curr_delay; - ModCC * curr_mod; - StompCC * curr_stomp; - - int continuous_control( const Mustang::Cmd & cmd ); - int discrete_control( const Mustang::Cmd & cmd ); - - void handle_parm_dump(void); - - void updateAmpObj(void); - void updateReverbObj(void); - void updateDelayObj(void); - void updateModObj(void); - void updateStompObj(void); + AmpCC * getAmp( void ) { return curr_amp;} + ReverbCC * getReverb( void ) { return curr_reverb;} + DelayCC * getDelay( void ) { return curr_delay;} + ModCC * getMod( void ) { return curr_mod;} + StompCC * getStomp( void ) { return curr_stomp;} }; -#endif // MUSTANG_H + +#endif diff --git a/mustang_midi.cpp b/mustang_midi.cpp index 96bb152..6501ebd 100644 --- a/mustang_midi.cpp +++ b/mustang_midi.cpp @@ -1,20 +1,26 @@ #include #include +#include +#include #include #include #include "mustang.h" +#if 0 #include "amp.h" #include "reverb.h" #include "delay.h" #include "mod.h" #include "stomp.h" +#endif static Mustang mustang; static int channel; +#if 0 + void message_action( double deltatime, std::vector< unsigned char > *message, void *userData ) { #if 0 unsigned int nBytes = message->size(); @@ -125,6 +131,8 @@ void message_action( double deltatime, std::vector< unsigned char > *message, vo } +#endif + // void errorcallback( RtError::Type type, const std::string & detail, void *userData ) { // std::cout << "Error: Code = " << type << ", Msg: " << detail << "\n"; // } @@ -149,12 +157,18 @@ int main( int argc, const char **argv ) { if ( endptr == argv[0] ) usage(); if ( channel < 0 || channel > 15 ) usage(); - int rc = mustang.start_amp(); - if (rc) { - std::cout << "Fender USB initialization failed: " << rc << "\n"; - return 8; + if ( 0 != mustang.initialize() ) { + fprintf( stderr, "Cannot setup USB communication\n" ); + exit( 1 ); + } + if ( 0 != mustang.commStart() ) { + fprintf( stderr, "Thread setup and init failed\n" ); + exit( 1 ); } + fprintf( stderr, "Setup done!\n" ); + +#if 0 RtMidiIn *input_handler = new RtMidiIn(); // See if we have any ports @@ -171,9 +185,23 @@ int main( int argc, const char **argv ) { // Don't want sysex, timing, active sense input_handler->ignoreTypes( true, true, true ); +#endif + // Block and wait for signal pause(); - delete input_handler; + if ( 0 != mustang.commShutdown() ) { + fprintf( stderr, "Thread shutdown failed\n" ); + exit( 1 ); + } + if ( 0 != mustang.deinitialize() ) { + fprintf( stderr, "USB shutdown failed\n" ); + exit( 1 ); + } + + fprintf( stderr, "Shutdown complete!\n" ); + + // delete input_handler; return 0; + } diff --git a/reverb.cpp b/reverb.cpp index 080057b..5b5877b 100644 --- a/reverb.cpp +++ b/reverb.cpp @@ -1,6 +1,7 @@ #include "reverb.h" #include "mustang.h" +#include "constants.h" int ReverbCC::continuous_control( int parm5, int parm6, int parm7, int value ) { diff --git a/reverb.h b/reverb.h index f9eb0d1..3bb4ec8 100644 --- a/reverb.h +++ b/reverb.h @@ -3,19 +3,30 @@ #ifndef _REVERB_H #define _REVERB_H +#include + class Mustang; class ReverbCC { protected: Mustang * amp; + unsigned char model[2]; + unsigned char slot; int continuous_control( int parm5, int parm6, int parm7, int value ); public: - ReverbCC( Mustang * theAmp ) : amp(theAmp) {} + ReverbCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : + amp(theAmp), + slot(theSlot) + { + memcpy( this->model, model, 2 ); + } int dispatch( int cc, int value ); + const unsigned char *getModel( void ) { return model;} + const unsigned char getSlot( void ) { return slot;} private: // Level @@ -33,7 +44,7 @@ private: class NullReverbCC : public ReverbCC { public: - NullReverbCC( Mustang * theAmp ) : ReverbCC(theAmp) {} + NullReverbCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : ReverbCC(theAmp,model,theSlot) {} private: int cc59( int value ) { return 0;} int cc60( int value ) { return 0;} diff --git a/stomp.cpp b/stomp.cpp index f027d77..6595ada 100644 --- a/stomp.cpp +++ b/stomp.cpp @@ -1,6 +1,7 @@ #include "stomp.h" #include "mustang.h" +#include "constants.h" int StompCC::continuous_control( int parm5, int parm6, int parm7, int value ) { diff --git a/stomp.h b/stomp.h index 06770da..8132756 100644 --- a/stomp.h +++ b/stomp.h @@ -3,20 +3,31 @@ #ifndef _STOMP_H #define _STOMP_H +#include + class Mustang; class StompCC { protected: Mustang * amp; - + unsigned char model[2]; + unsigned char slot; + int continuous_control( int parm5, int parm6, int parm7, int value ); int discrete_control( int parm5, int parm6, int parm7, int value ); public: - StompCC( Mustang * theAmp ) : amp(theAmp) {} + StompCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : + amp(theAmp), + slot(theSlot) + { + memcpy( this->model, model, 2 ); + } int dispatch( int cc, int value ); + const unsigned char *getModel( void ) { return model;} + const unsigned char getSlot( void ) { return slot;} private: virtual int cc29( int value ) = 0; @@ -29,7 +40,7 @@ private: class OverdriveCC : public StompCC { public: - OverdriveCC( Mustang * theAmp ) : StompCC(theAmp) {} + OverdriveCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : StompCC(theAmp,model,theSlot) {} private: // Level virtual int cc29( int value ) { return continuous_control( 0x00, 0x00, 0x01, value );} @@ -46,7 +57,7 @@ private: class WahCC : public StompCC { public: - WahCC( Mustang * theAmp ) : StompCC(theAmp) {} + WahCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : StompCC(theAmp,model,theSlot) {} private: // Mix virtual int cc29( int value ) { return continuous_control( 0x00, 0x00, 0x01, value );} @@ -66,7 +77,7 @@ private: class FuzzCC : public StompCC { public: - FuzzCC( Mustang * theAmp ) : StompCC(theAmp) {} + FuzzCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : StompCC(theAmp,model,theSlot) {} private: // Level virtual int cc29( int value ) { return continuous_control( 0x00, 0x00, 0x01, value );} @@ -83,7 +94,7 @@ private: class FuzzTouchWahCC : public StompCC { public: - FuzzTouchWahCC( Mustang * theAmp ) : StompCC(theAmp) {} + FuzzTouchWahCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : StompCC(theAmp,model,theSlot) {} private: // Level virtual int cc29( int value ) { return continuous_control( 0x00, 0x00, 0x01, value );} @@ -100,7 +111,7 @@ private: class SimpleCompCC : public StompCC { public: - SimpleCompCC( Mustang * theAmp ) : StompCC(theAmp) {} + SimpleCompCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : StompCC(theAmp,model,theSlot) {} private: // Type virtual int cc29( int value ) { @@ -116,7 +127,7 @@ private: class CompCC : public StompCC { public: - CompCC( Mustang * theAmp ) : StompCC(theAmp) {} + CompCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : StompCC(theAmp,model,theSlot) {} private: // Level virtual int cc29( int value ) { return continuous_control( 0x00, 0x00, 0x01, value );} @@ -133,7 +144,7 @@ private: class RangerCC : public StompCC { public: - RangerCC( Mustang * theAmp ) : StompCC(theAmp) {} + RangerCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot) : StompCC(theAmp,model,theSlot) {} private: // Level virtual int cc29( int value ) { return continuous_control( 0x00, 0x00, 0x01, value );} @@ -150,7 +161,7 @@ private: class GreenBoxCC : public StompCC { public: - GreenBoxCC( Mustang * theAmp ) : StompCC(theAmp) {} + GreenBoxCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : StompCC(theAmp,model,theSlot) {} private: // Level virtual int cc29( int value ) { return continuous_control( 0x00, 0x00, 0x01, value );} @@ -167,7 +178,7 @@ private: class OrangeBoxCC : public StompCC { public: - OrangeBoxCC( Mustang * theAmp ) : StompCC(theAmp) {} + OrangeBoxCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : StompCC(theAmp,model,theSlot) {} private: // Level virtual int cc29( int value ) { return continuous_control( 0x00, 0x00, 0x01, value );} @@ -184,7 +195,7 @@ private: class BlackBoxCC : public StompCC { public: - BlackBoxCC( Mustang * theAmp ) : StompCC(theAmp) {} + BlackBoxCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : StompCC(theAmp,model,theSlot) {} private: // Level virtual int cc29( int value ) { return continuous_control( 0x00, 0x00, 0x01, value );} @@ -201,7 +212,7 @@ private: class BigFuzzCC : public StompCC { public: - BigFuzzCC( Mustang * theAmp ) : StompCC(theAmp) {} + BigFuzzCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : StompCC(theAmp,model,theSlot) {} private: // Level virtual int cc29( int value ) { return continuous_control( 0x00, 0x00, 0x01, value );} @@ -218,7 +229,7 @@ private: class NullStompCC : public StompCC { public: - NullStompCC( Mustang * theAmp ) : StompCC(theAmp) {} + NullStompCC( Mustang * theAmp, const unsigned char *model, const unsigned char theSlot ) : StompCC(theAmp,model,theSlot) {} private: virtual int cc29( int value ) { return 0;} virtual int cc30( int value ) { return 0;} diff --git a/stomp_models.cpp b/stomp_models.cpp new file mode 100644 index 0000000..54d5a3e --- /dev/null +++ b/stomp_models.cpp @@ -0,0 +1,16 @@ +#include "stomp_models.h" + +const unsigned char overdrive_id[] = { 0x3c, 0x00 }; +const unsigned char wah_id[] = { 0x49, 0x00 }; +const unsigned char touch_wah_id[] = { 0x4a, 0x00 }; +const unsigned char fuzz_id[] = { 0x1a, 0x00 }; +const unsigned char fuzz_twah_id[] = { 0x1c, 0x00 }; +const unsigned char simple_comp_id[] = { 0x88, 0x00 }; +const unsigned char comp_id[] = { 0x07, 0x00 }; + +const unsigned char range_boost_id[] = { 0x03, 0x00 }; +const unsigned char green_box_id[] = { 0xba, 0x00 }; +const unsigned char orange_box_id[] = { 0x10, 0x00 }; +const unsigned char black_box_id[] = { 0x11, 0x00 }; +const unsigned char big_fuzz_id[] = { 0x0f, 0x00 }; + diff --git a/stomp_models.h b/stomp_models.h new file mode 100644 index 0000000..f2379b0 --- /dev/null +++ b/stomp_models.h @@ -0,0 +1,19 @@ +#ifndef STOMP_MODELS_H +#define STOMP_MODELS_H + +extern const unsigned char overdrive_id[]; +extern const unsigned char wah_id[]; +extern const unsigned char touch_wah_id[]; +extern const unsigned char fuzz_id[]; +extern const unsigned char fuzz_twah_id[]; +extern const unsigned char simple_comp_id[]; +extern const unsigned char comp_id[]; + +// v2 only +extern const unsigned char range_boost_id[]; +extern const unsigned char green_box_id[]; +extern const unsigned char orange_box_id[]; +extern const unsigned char black_box_id[]; +extern const unsigned char big_fuzz_id[]; + +#endif