mustang-midi-bridge/mustang.cpp
2016-07-24 21:45:35 -04:00

1155 lines
28 KiB
C++

#include "mustang.h"
#include <cstdio>
#include <cmath>
#include "magic.h"
#include "amp.h"
#include "reverb.h"
#include "delay.h"
#include "mod.h"
#include "stomp.h"
#include "amp_defaults.h"
#include "reverb_defaults.h"
#include "delay_defaults.h"
#include "mod_defaults.h"
#include "stomp_defaults.h"
#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( void ) {
// Make model select effective
memset( execute, 0x00, 64 );
execute[0] = 0x1c;
execute[1] = 0x03;
}
void *
Mustang::threadStarter( void *self ) {
((Mustang *)self)->handleInput();
return NULL;
}
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;
}
// Retry on short read
if ( total_count!=64 ) continue;
total_count = 0;
#if 0
for ( int i=0; i<64; i++ ) fprintf( stderr, "%02x ", read_buf[i] );
fprintf( stderr, "\n" );
#endif
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 );
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::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;
const unsigned char *model = data + MODEL;
const unsigned char slot = data[FXSLOT];
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:
buffer = amp_none;
break;
case 1:
buffer = f57_deluxe;
break;
case 2:
buffer = f59_bassman;
break;
case 3:
buffer = f57_champ;
break;
case 4:
buffer = f65_deluxe;
break;
case 5:
buffer = f65_princeton;
break;
case 6:
buffer = f65_twin;
break;
case 7:
buffer = f_supersonic;
break;
case 8:
buffer = brit_60;
break;
case 9:
buffer = brit_70;
break;
case 10:
buffer = brit_80;
break;
case 11:
buffer = us_90;
break;
case 12:
buffer = metal_2k;
break;
default:
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;
}
}
else {
fprintf( stderr, "W - Amp select %d not supported\n", ord );
return 0;
}
}
// 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[AMP_STATE], buffer, 64);
// updateAmpObj("a");
// 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;
// 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::setReverb( int ord ) {
if ( tuner_active ) return 0;
int rc, count;
unsigned char scratch[64];
unsigned char *buffer;
switch (ord) {
case 0:
buffer = reverb_none;
break;
case 1:
buffer = small_hall;
break;
case 2:
buffer = large_hall;
break;
case 3:
buffer = small_room;
break;
case 4:
buffer = large_room;
break;
case 5:
buffer = small_plate;
break;
case 6:
buffer = large_plate;
break;
case 7:
buffer = ambient;
break;
case 8:
buffer = arena;
break;
case 9:
buffer = spring_63;
break;
case 10:
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:
buffer = pitch_shifter;
break;
default:
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;
}
}
buffer[FXSLOT] = dsp_parms[MOD_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[MOD_STATE], buffer, 64);
// updateModObj();
return rc;
}
int
Mustang::setStomp( int ord ) {
if ( tuner_active ) return 0;
int rc, count;
unsigned char scratch[64];
unsigned char *buffer;
switch (ord) {
case 0:
buffer = stomp_none;
break;
case 1:
buffer = overdrive;
break;
case 2:
buffer = wah;
break;
case 3:
buffer = touch_wah;
break;
case 4:
buffer = fuzz;
break;
case 5:
if ( isV2 ) {
fprintf( stderr, "W - Stomp select %d not supported\n", ord );
return 0;
}
else {
buffer = fuzz_touch_wah;
}
break;
case 6:
buffer = simple_comp;
break;
case 7:
buffer = compressor;
break;
default:
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;
}
}
buffer[FXSLOT] = dsp_parms[STOMP_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[STOMP_STATE], buffer, 64);
// updateStompObj();
return rc;
}
int
Mustang::continuous_control( const Mustang::Cmd & cmd ) {
if ( tuner_active ) return 0;
int rc, count;
unsigned char buffer[64];
memset(buffer, 0x00, 64);
buffer[0] = 0x05;
buffer[1] = 0xc3;
buffer[2] = cmd.parm2;
buffer[3] = dsp_parms[cmd.state_index][MODEL];
// 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;
unsigned short eff_value = magic_values[index];
buffer[9] = eff_value & 0xff;
buffer[10] = (eff_value >> 8) & 0xff;
// 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 rc;
}
int
Mustang::discrete_control( const Mustang::Cmd & cmd ) {
if ( tuner_active ) return 0;
int rc, count;
unsigned char buffer[64];
memset(buffer, 0x00, 64);
buffer[0] = 0x05;
buffer[1] = 0xc3;
buffer[2] = cmd.parm2;
buffer[3] = dsp_parms[cmd.state_index][MODEL];
buffer[5] = cmd.parm5;
buffer[6] = cmd.parm6;
buffer[7] = cmd.parm7;
// Discrete value
buffer[9] = cmd.value;
// 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 rc;
}
int
Mustang::patchChange( int patch ) {
if ( tuner_active ) return 0;
int rc, count;
unsigned char buffer[64], data[7][64];
memset(buffer, 0x00, 64);
buffer[0] = 0x1c;
buffer[1] = 0x01;
buffer[2] = 0x01;
buffer[PATCH_SLOT] = patch;
buffer[6] = 0x01;
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( 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 rc;
}