Hi Takashi, This has more features: - PCM-Volume adjusted to MasteVolumeSlider setting at device start. - Direct Monitoring Functions adjustable directly on the US428 - Alsa Sequencer Output port for applications to receive the US428 sliders etc.
please add the missing files attached + commit the patch. Danke, Karsten
Index: alsa-tools/us428control/Cus428State.cc =================================================================== RCS file: /cvsroot/alsa/alsa-tools/us428control/Cus428State.cc,v retrieving revision 1.1 diff -u -r1.1 Cus428State.cc --- alsa-tools/us428control/Cus428State.cc 6 Oct 2003 15:57:24 -0000 1.1 +++ alsa-tools/us428control/Cus428State.cc 23 Oct 2003 17:01:45 -0000 @@ -20,12 +20,14 @@ #include <stdio.h> #include <string.h> -#include "Cus428State.h" +#include <alsa/asoundlib.h> +#include "Cus428Midi.h" extern int verbose; -void -us428_lights::init_us428_lights() + + +void us428_lights::init_us428_lights() { int i = 0; memset(this, 0, sizeof(*this)); @@ -33,8 +35,14 @@ Light[ i].Offset = i + 0x19; } -int -Cus428State::LightSend() + +void Cus428State::InitDevice(void) +{ + SliderChangedTo(eFaderM, ((unsigned char*)(us428ctls_sharedmem->CtlSnapShot + us428ctls_sharedmem->CtlSnapShotLast))[eFaderM]); +} + + +int Cus428State::LightSend() { int Next = us428ctls_sharedmem->p4outLast + 1; if(Next < 0 || Next >= N_us428_p4out_BUFS) @@ -44,14 +52,8 @@ return us428ctls_sharedmem->p4outLast = Next; } -void -Cus428State::SliderChangedTo(int S, unsigned char New) +void Cus428State::SendVolume(usX2Y_volume &V) { - if ((S >= eFader4 || S < 0) && S != eFaderM) - return; - - usX2Y_volume V; - V.SetTo(S, New); int Next = us428ctls_sharedmem->p4outLast + 1; if (Next < 0 || Next >= N_us428_p4out_BUFS) Next = 0; @@ -60,24 +62,107 @@ us428ctls_sharedmem->p4outLast = Next; } +void Cus428State::SliderChangedTo(int S, unsigned char New) +{ + if (StateInputMonitor() && S <= eFader3 + || S == eFaderM) { + usX2Y_volume &V = Volume[S >= eFader4 ? eFader4 : S]; + V.SetTo(S, New); + if (S == eFaderM || !LightIs(eL_Mute0 + S)) + SendVolume(V); + } else + Midi.SendMidiControl(0x40 + S, ((unsigned char*)us428_ctls)[S] / 2); + +} -void -Cus428State::KnobChangedTo(eKnobs K, bool V) + +void Cus428State::KnobChangedTo(eKnobs K, bool V) { - switch (K) { - case eK_InputMonitor: - if (verbose > 1) - printf("Knob InputMonitor now %i", V); + switch (K & ~(StateInputMonitor() ? 3 : -1)) { + case eK_Select0: if (V) { - LightSet(eL_InputMonitor, ! LightIs(eL_InputMonitor)); + int S = eL_Select0 + (K & 7); + Light[eL_Select0 / 8].Value = 0; + LightSet(S, !LightIs(S)); LightSend(); } - if (verbose > 1) - printf(" Light is %i\n", LightIs(eL_InputMonitor)); + break; + case eK_Mute0: + if (V) { + int M = eL_Mute0 + (K & 7); + LightSet(M, !LightIs(M)); + LightSend(); + if (StateInputMonitor()) { + usX2Y_volume V = Volume[M - eL_Mute0]; + if (LightIs(M)) + V.LH = V.LL = V.RL = V.RH = 0; + SendVolume(V); + } + } break; default: - if (verbose > 1) - printf("Knob %i now %i\n", K, V); + switch (K) { + case eK_InputMonitor: + if (verbose > 1) + printf("Knob InputMonitor now %i", V); + if (V) { + if (StateInputMonitor()) { + SelectInputMonitor = Light[0].Value; + MuteInputMonitor = Light[2].Value; + } else { + Select = Light[0].Value; + Mute = Light[2].Value; + } + LightSet(eL_InputMonitor, ! StateInputMonitor()); + Light[0].Value = StateInputMonitor() ? SelectInputMonitor : Select; + Light[2].Value = StateInputMonitor() ? MuteInputMonitor : Mute; + LightSend(); + } + if (verbose > 1) + printf(" Light is %i\n", LightIs(eL_InputMonitor)); + break; + default: + if (verbose > 1) + printf("Knob %i now %i\n", K, V); + Midi.SendMidiControl(K, V); + } } } + +void Cus428State::WheelChangedTo(E_In84 W, char Diff) +{ + char Param; + switch (W) { + case eWheelPan: + if (StateInputMonitor() && Light[0].Value) { + int index = 0; + + while( index < 4 && (1 << index) != Light[0].Value) + index++; + + if (index >= 4) + return; + + Volume[index].PanTo(Diff, us428_ctls->Knob(eK_SET)); + if (!LightIs(eL_Mute0 + index)) + SendVolume(Volume[index]); + return; + } + Param = 0x4D; + break; + case eWheelGain: + Param = 0x48; + break; + case eWheelFreq: + Param = 0x49; + break; + case eWheelQ: + Param = 0x4A; + break; + case eWheel: + Param = 0x60; + break; + } + Midi.SendMidiControl(Param, ((unsigned char*)us428_ctls)[W]); +} Index: alsa-tools/us428control/Cus428State.h =================================================================== RCS file: /cvsroot/alsa/alsa-tools/us428control/Cus428State.h,v retrieving revision 1.1 diff -u -r1.1 Cus428State.h --- alsa-tools/us428control/Cus428State.h 6 Oct 2003 15:57:24 -0000 1.1 +++ alsa-tools/us428control/Cus428State.h 23 Oct 2003 17:01:45 -0000 @@ -23,24 +23,79 @@ #include "Cus428_ctls.h" -class Cus428State: public us428_lights, public Cus428_ctls{ +class Cus428State: public us428_lights{ public: Cus428State(struct us428ctls_sharedmem* Pus428ctls_sharedmem) :us428ctls_sharedmem(Pus428ctls_sharedmem) + ,MuteInputMonitor(0) + ,Mute(0) + ,us428_ctls(0) { init_us428_lights(); + for (int v = 0; v < 5; ++v) { + Volume[v].init(v); + } } enum eKnobs{ - eK_RECORD = 72, - eK_PLAY = 73, + eK_RECORD = 72, + eK_PLAY, eK_STOP, - eK_InputMonitor = 80 + eK_FFWD, + eK_REW, + eK_SOLO, + eK_REC, + eK_NULL, + eK_InputMonitor, // = 80 + eK_BANK_L, + eK_BANK_R, + eK_LOCATE_L, + eK_LOCATE_R, + eK_SET = 85, + eK_INPUTCD = 87, + eK_HIGH = 90, + eK_HIMID, + eK_LOWMID, + eK_LOW, + eK_Select0 = 96, + eK_Mute0 = 104, + eK_Mute1, + eK_Mute2, + eK_Mute3, + eK_Mute4, + eK_Mute5, + eK_Mute6, + eK_Mute7, + eK_AUX1 = 120, + eK_AUX2, + eK_AUX3, + eK_AUX4, + eK_ASGN, + eK_F1, + eK_F2, + eK_F3, }; + void InitDevice(void); void KnobChangedTo(eKnobs K, bool V); void SliderChangedTo(int S, unsigned char New); + void WheelChangedTo(E_In84 W, char Diff); + Cus428_ctls *Set_us428_ctls(Cus428_ctls *New) { + Cus428_ctls *Old = us428_ctls; + us428_ctls = New; + return Old; + } private: int LightSend(); + void SendVolume(usX2Y_volume &V); struct us428ctls_sharedmem* us428ctls_sharedmem; + bool StateInputMonitor() { + return LightIs(eL_InputMonitor); + } + usX2Y_volume_t Volume[5]; + char MuteInputMonitor, + Mute, + SelectInputMonitor, + Select; + Cus428_ctls *us428_ctls; }; extern Cus428State* OneState; Index: alsa-tools/us428control/Cus428_ctls.cc =================================================================== RCS file: /cvsroot/alsa/alsa-tools/us428control/Cus428_ctls.cc,v retrieving revision 1.1 diff -u -r1.1 Cus428_ctls.cc --- alsa-tools/us428control/Cus428_ctls.cc 6 Oct 2003 15:57:24 -0000 1.1 +++ alsa-tools/us428control/Cus428_ctls.cc 23 Oct 2003 17:01:45 -0000 @@ -31,27 +31,31 @@ for (int m = 0; m < n; m++) printf(" "); for (; n < sizeof(*this); n++) - printf("%02hhX ", ((char*)this)[ n]); + printf("%02hhX ", ((char*)this)[n]); printf("\n"); } void Cus428_ctls::analyse(Cus428_ctls& Previous, unsigned n) { - for (; n < 9; n++) { //Sliders - char Diff = ((unsigned char*)this)[ n] - ((unsigned char*)&Previous)[ n]; + OneState->Set_us428_ctls(this); + for (; n < 9; n++) { //Sliders + char Diff = ((unsigned char*)this)[n] - ((unsigned char*)&Previous)[n]; if (Diff) - OneState->SliderChangedTo(n, ((unsigned char*)this)[ n]); + OneState->SliderChangedTo(n, ((unsigned char*)this)[n]); } - for (; n < 16; n++) { //Knobs - unsigned char Diff = ((unsigned char*)this)[ n] ^ ((unsigned char*)&Previous)[ n]; + for (; n < 16; n++) { //Knobs + unsigned char Diff = ((unsigned char*)this)[n] ^ ((unsigned char*)&Previous)[n]; unsigned o = 0; while (o < 8) { if (Diff & (1 << o)) - OneState->KnobChangedTo((Cus428State::eKnobs)(8*n + o), ((unsigned char*)this)[ n] & (1 << o)); + OneState->KnobChangedTo((Cus428State::eKnobs)(8*n + o), ((unsigned char*)this)[n] & (1 << o)); ++o; } } - for (; n < sizeof(*this); n++) - ; //wheels + for (; n < sizeof(*this); n++) { //wheels + char Diff = ((unsigned char*)this)[ n] - ((unsigned char*)&Previous)[n]; + if (Diff) + OneState->WheelChangedTo((E_In84)n, Diff); + } } Index: alsa-tools/us428control/Cus428_ctls.h =================================================================== RCS file: /cvsroot/alsa/alsa-tools/us428control/Cus428_ctls.h,v retrieving revision 1.1 diff -u -r1.1 Cus428_ctls.h --- alsa-tools/us428control/Cus428_ctls.h 6 Oct 2003 15:57:24 -0000 1.1 +++ alsa-tools/us428control/Cus428_ctls.h 23 Oct 2003 17:01:46 -0000 @@ -27,6 +27,9 @@ public: void dump(int n = 0); void analyse(Cus428_ctls& Previous, unsigned n = 0); + bool Knob( int K) { + return ((char*)this)[K / 8] & (1 << K % 8); + } }; #endif Index: alsa-tools/us428control/Makefile.am =================================================================== RCS file: /cvsroot/alsa/alsa-tools/us428control/Makefile.am,v retrieving revision 1.1 diff -u -r1.1 Makefile.am --- alsa-tools/us428control/Makefile.am 6 Oct 2003 15:57:24 -0000 1.1 +++ alsa-tools/us428control/Makefile.am 23 Oct 2003 17:01:46 -0000 @@ -3,8 +3,7 @@ bin_PROGRAMS = us428control -us428control_SOURCES = us428control.cc Cus428State.cc Cus428_ctls.cc -us428control_HEADERS = Cus428State.h Cus428_ctls.h usbus428ctldefs.h +us428control_SOURCES = us428control.cc Cus428State.cc Cus428_ctls.cc Cus428Midi.cc EXTRA_DIST = depcomp Index: alsa-tools/us428control/configure.in =================================================================== RCS file: /cvsroot/alsa/alsa-tools/us428control/configure.in,v retrieving revision 1.1 diff -u -r1.1 configure.in --- alsa-tools/us428control/configure.in 6 Oct 2003 15:57:24 -0000 1.1 +++ alsa-tools/us428control/configure.in 23 Oct 2003 17:01:46 -0000 @@ -1,5 +1,5 @@ AC_INIT(us428control.cc) -AM_INIT_AUTOMAKE(us428control, 0.1) +AM_INIT_AUTOMAKE(us428control, 0.3) AC_PROG_CXX AC_PROG_INSTALL AC_HEADER_STDC Index: alsa-tools/us428control/us428control.cc =================================================================== RCS file: /cvsroot/alsa/alsa-tools/us428control/us428control.cc,v retrieving revision 1.1 diff -u -r1.1 us428control.cc --- alsa-tools/us428control/us428control.cc 6 Oct 2003 15:57:24 -0000 1.1 +++ alsa-tools/us428control/us428control.cc 23 Oct 2003 17:01:46 -0000 @@ -31,6 +31,7 @@ #include <alsa/asoundlib.h> #include "Cus428_ctls.h" #include "Cus428State.h" +#include "Cus428Midi.h" #define PROGNAME "us428control" @@ -41,6 +42,8 @@ int verbose = 1; +Cus428Midi Midi; + static void error(const char *fmt, ...) { @@ -56,7 +59,7 @@ static void usage(void) { - printf("Tascam US-428 Contol\n"); + printf("Tascam US-428 Control\n"); printf("version %s\n", VERSION); printf("usage: "PROGNAME" [-v verbosity_level 0..2] [-c card] [-D device] [-u usb-device]\n"); } @@ -104,8 +107,10 @@ perror("mmap failed:"); return -ENOMEM; } + Midi.CreatePorts(); us428ctls_sharedmem->CtlSnapShotRed = us428ctls_sharedmem->CtlSnapShotLast; OneState = new Cus428State(us428ctls_sharedmem); + OneState->InitDevice(); while (1) { int x = poll(&pfds,1,-1); if (verbose > 1 || pfds.revents & (POLLERR|POLLHUP)) Index: alsa-tools/us428control/usbus428ctldefs.h =================================================================== RCS file: /cvsroot/alsa/alsa-tools/us428control/usbus428ctldefs.h,v retrieving revision 1.1 diff -u -r1.1 usbus428ctldefs.h --- alsa-tools/us428control/usbus428ctldefs.h 6 Oct 2003 15:57:24 -0000 1.1 +++ alsa-tools/us428control/usbus428ctldefs.h 23 Oct 2003 17:01:46 -0000 @@ -17,7 +17,12 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -enum E_In84{ +#ifdef __cplusplus +#include <string.h> +extern int verbose; +#endif + +enum E_In84 { eFader0 = 0, eFader1, eFader2, @@ -76,18 +81,63 @@ }; typedef struct usX2Y_volume { - unsigned char Channel, - LH, - LL, - RH, - RL; + unsigned char Channel, + LH, + LL, + RH, + RL; + unsigned char Slider; + char Pan, + Mute; #ifdef __cplusplus public: + void init(unsigned char _Channel) { + memset(this, 0, sizeof(*this)); + Channel = _Channel; + } int Scale(){return 0x40;} + + void calculate() { + int lPan = (int)Pan * Slider / 0x80; + int ValL = (Slider - lPan) * Scale(); + LH = ValL >> 8; + LL = ValL; + int ValR = (Slider + lPan) * Scale(); + RH = ValR >> 8; + RL = ValR; + if (2 < verbose) + printf("S=% 3i, P=% 3i, lP=% 3i, VL=%05i, VR=%05i\n", (int)Slider, (int)Pan, (int)lPan, ValL, ValR); + } + void SetTo(unsigned char _Channel, int RawValue){ + Slider = RawValue; Channel = eFaderM == _Channel ? 4 : _Channel; - LH = RH = (RawValue *= Scale()) >> 8; - LL = RL = RawValue; + calculate(); + } + void PanTo(int RawValue, bool Grob) { + int NewPan; + if (Grob) { + static int GrobVals[] = {-128, -64, 0, 64, 127}; + int i = 4; + while (i >= 0 && GrobVals[i] > Pan) + i--; + if (GrobVals[i] != Pan && RawValue < 0) + i++; + + if (i >= 0) { + if ((i += RawValue) >= 0 && i < 5) + NewPan = GrobVals[i]; + else + return; + } + + } else { + NewPan = Pan + RawValue; + } + if (NewPan < -128 || NewPan > 127) + return; + Pan = NewPan; + calculate(); } #endif } usX2Y_volume_t; @@ -97,16 +147,18 @@ #ifdef __cplusplus public: enum eLight{ + eL_Select0 = 0, + eL_Mute0 = 16, eL_InputMonitor = 25 }; - bool LightIs(eLight L){ + bool LightIs(int L){ return Light[L / 8].Value & (1 << (L % 8)); } - void LightSet(eLight L, bool Value){ + void LightSet(int L, bool Value){ if (Value) Light[L / 8].Value |= (1 << (L % 8)); else - Light[L / 8].Value &= (~1 << (L % 8)); + Light[L / 8].Value &= ~(1 << (L % 8)); } void init_us428_lights(); #endif
#include <alsa/asoundlib.h> #include "Cus428Midi.h" char Cus428Midi::KnobParam[] = { 0x17, 0x16, 0x15, 0x14, 0x13, 0x2A, 0x29, 0x28, -1, 0x10, 0x11, 0x18, 0x19, 0x1A, -1, -1, -1, -1, 0x2C, 0x2D, 0x2E, 0x2F, -1, -1, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0, 1, 2, 3, 4, 5, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, };
#include <sound/asequencer.h> #include "Cus428State.h" class Cus428Midi { public: Cus428Midi(): Seq(0){} int CreatePorts(){ int Err; if (0 <= (Err = snd_seq_open(&Seq, "default", SND_SEQ_OPEN_DUPLEX, SND_SEQ_NONBLOCK))) { snd_seq_set_client_name(Seq, "US-428"); Err = snd_seq_create_simple_port(Seq, "Controls", SNDRV_SEQ_PORT_CAP_READ //|SNDRV_SEQ_PORT_CAP_WRITE FIXME: Next Step is to make Lights switchable |SNDRV_SEQ_PORT_CAP_SUBS_READ /*|SNDRV_SEQ_PORT_CAP_SUBS_WRITE*/, SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC); if (Err >= 0) { Port = Err; snd_seq_ev_clear(&Ev); snd_seq_ev_set_direct(&Ev); snd_seq_ev_set_source(&Ev, Port); snd_seq_ev_set_subs(&Ev); } } return Err; } int SendMidiControl(char Param, char Val){ snd_seq_ev_set_controller(&Ev, 15, Param, Val & 0x7F); SubMitEvent(); return 0; } int SendMidiControl(Cus428State::eKnobs K, bool Down){ return SendMidiControl(KnobParam[K - Cus428State::eK_RECORD], Down ? 0x7F : 0); } private: snd_seq_t *Seq; int Port; snd_seq_event_t Ev; int SubMitEvent(){ snd_seq_event_output(Seq, &Ev); snd_seq_drain_output(Seq); return 0; } static char KnobParam[]; }; extern Cus428Midi Midi;