]> git.alsa-project.org Git - alsa-tools.git/commitdiff
Added MMC support by Rui Nuno Capela <rncbc@rncbc.org>
authorTakashi Iwai <tiwai@suse.de>
Wed, 28 Jul 2004 15:56:45 +0000 (15:56 +0000)
committerTakashi Iwai <tiwai@suse.de>
Wed, 28 Jul 2004 15:56:45 +0000 (15:56 +0000)
MMC support has been improved and transport LEDs is getting almost
functional. Tascam control protocol sysex decoding is also complete (LEDs
control mainly).

us428control/Cus428Midi.cc
us428control/Cus428Midi.h
us428control/Cus428State.cc
us428control/Cus428State.h
us428control/configure.in
us428control/us428control.cc
us428control/usbus428ctldefs.h

index 2de23915bf926416a536d55d923c442c3a7094ca..ff25084760cce913496d68277c559a2ab0546833 100644 (file)
@@ -79,3 +79,173 @@ char Cus428Midi::KnobParam[] = {
        0x36,
        0x37,
        };
+
+extern int verbose;
+
+
+// Parse and dispatch input MIDI events.
+void Cus428Midi::ProcessMidiEvents()
+{
+       snd_seq_event_t *ev;
+       unsigned char *data;
+
+       do {
+               ev = NULL;
+               snd_seq_event_input(Seq, &ev);
+               if (ev == NULL)
+                       break;
+               switch (ev->type) {
+               case SND_SEQ_EVENT_SYSEX:
+                       data = (unsigned char *) ev->data.ext.ptr;
+                       if (data[1] == 0x7f && data[3] == 0x06) {
+                               // MMC Command code is in data[4]...
+                               if (verbose > 1)
+                                       fprintf(stderr, "MMC Command 0x%02x: ", data[4]);
+                               switch (data[4]) {
+                               case MMC_CMD_STOP:
+                                       if (verbose > 1)
+                                               fprintf(stderr, "STOP.\n");
+                                       OneState->TransportSet(T_STOP, true);
+                                       break;
+                               case MMC_CMD_PLAY:
+                               case MMC_CMD_DEFERRED_PLAY:
+                                       if (verbose > 1)
+                                               fprintf(stderr, "PLAY.\n");
+                                       OneState->TransportSet(T_PLAY, true);
+                                       break;
+                               case MMC_CMD_FAST_FORWARD:
+                                       if (verbose > 1)
+                                               fprintf(stderr, "FFWD.\n");
+                                       OneState->TransportSet(T_F_FWD, true);
+                                       break;
+                               case MMC_CMD_REWIND:
+                                       if (verbose > 1)
+                                               fprintf(stderr, "REW.\n");
+                                       OneState->TransportSet(T_REW, true);
+                                       break;
+                               case MMC_CMD_RECORD_STROBE:
+                               case MMC_CMD_RECORD_PAUSE:
+                                       if (verbose > 1)
+                                               fprintf(stderr, "RECORD ON.\n");
+                                       OneState->TransportSet(T_RECORD, true);
+                                       break;
+                               case MMC_CMD_RECORD_EXIT:
+                                       if (verbose > 1)
+                                               fprintf(stderr, "RECORD OFF.\n");
+                                       OneState->TransportSet(T_RECORD, false);
+                                       break;
+                               case MMC_CMD_LOCATE:
+                                       if (verbose > 1)
+                                               fprintf(stderr, "LOCATE WHEEL.\n");
+                                       OneState->LocateWheel(&data[7]);
+                                       break;
+                               case MMC_CMD_MMC_RESET:
+                                       if (verbose > 1)
+                                               fprintf(stderr, "MMC RESET.\n");
+                                       OneState->MmcReset();
+                                       break;
+                               default:
+                                       if (verbose > 1)
+                                               fprintf(stderr, "Not implemented.\n");
+                                       break;
+                               }
+                       }       // Look for Tascam US-224/US-428(?) specific LED codes.
+                       else if (data[1] == 0x4e && data[3] == 0x12) {
+                               if (verbose > 1)
+                                       fprintf(stderr, "TASCAM Command 0x%02x.\n", data[4]);
+                               // Transport LEDs.
+                               switch (data[4]) {
+                               case 0x01:              // Transport LEDs...
+                                       switch(data[5]) {
+                                       case 0x13:      // REWIND.
+                                               OneState->LightSet(Cus428State::eL_Rew,  data[6]);
+                                               OneState->LightSend();
+                                               break;
+                                       case 0x14:      // FFWD.
+                                               OneState->LightSet(Cus428State::eL_FFwd, data[6]);
+                                               OneState->LightSend();
+                                               break;
+                                       case 0x16:      // PLAY.
+                                               OneState->LightSet(Cus428State::eL_Play, data[6]);
+                                               OneState->LightSend();
+                                               break;
+                                       case 0x17:      // REC.
+                                               OneState->LightSet(Cus428State::eL_Record, data[6]);
+                                               OneState->LightSend();
+                                               break;
+                                       default:
+                                               break;
+                                       }
+                                       break;
+                               case 0x02:              // Mute LEDs
+                                       OneState->LightSet(Cus428State::eL_Mute0 + data[5], data[6]);
+                                       OneState->LightSend();
+                                       break;
+                               case 0x03:              // Select LEDs
+                                       OneState->LightSet(Cus428State::eL_Select0 + data[5], data[6]);
+                                       OneState->LightSend();
+                                       break;
+                               case 0x04:              // Record LEDs
+                                       OneState->LightSet(Cus428State::eL_Rec0 + data[5], data[6]);
+                                       OneState->LightSend();
+                                       break;
+                               case 0x05:              // Null LED
+                                       OneState->LightSet(Cus428State::eL_Null, data[5]);
+                                       OneState->LightSend();
+                                       break;
+                               case 0x06:              // Solo LED
+                                       OneState->LightSet(Cus428State::eL_Solo, data[5]);
+                                       OneState->LightSend();
+                                       break;
+                               case 0x07:              // Bank L LED
+                                       OneState->LightSet(Cus428State::eL_BankL, data[5]);
+                                       OneState->LightSend();
+                                       break;
+                               case 0x08:              // Bank R LED
+                                       OneState->LightSet(Cus428State::eL_BankR, data[5]);
+                                       OneState->LightSend();
+                                       break;
+                               case 0x10:              // Dump fader position.
+                                       OneState->SliderSend(data[5]);
+                                       break;
+                               }
+                       }
+                       break;
+               default:
+                       break;
+               }
+               snd_seq_free_event(ev);
+       }
+       while (snd_seq_event_input_pending(Seq, 0) > 0);
+}
+
+
+// Send MMC command.
+void Cus428Midi::SendMmcCommand(unsigned char MmcCmd, unsigned char *MmcData, unsigned char MmcLen)
+{
+       unsigned char  SysexSize;
+       unsigned char  SysexLen;
+       unsigned char *SysexData;
+
+       SysexSize = 6;
+       if (MmcLen > 0)
+               SysexSize += 1 + MmcLen;
+       SysexData = (unsigned char *) alloca(SysexSize);
+       SysexLen  = 0;
+
+       SysexData[SysexLen++] = 0xf0;   // Sysex header.
+       SysexData[SysexLen++] = 0x7f;   // Realtime sysex.
+       SysexData[SysexLen++] = 0x7f;   // All-caller-id.
+       SysexData[SysexLen++] = 0x06;   // MMC command mode.
+       SysexData[SysexLen++] = MmcCmd; // MMC command code.
+       if (MmcData && MmcLen > 0) {
+               SysexData[SysexLen++] = MmcLen;
+               memcpy(&SysexData[SysexLen], MmcData, MmcLen);
+               SysexLen += MmcLen;
+       }
+       SysexData[SysexLen++] = 0xf7;   // Sysex trailer.
+
+       snd_seq_ev_set_sysex(&Ev, SysexLen, SysexData);
+
+       SubMitEvent();
+}
index d3b08eb740abc5d0d615493ee1d988d1a4eccc40..05347b079996ac00acfa83790148cae09cbe2a98 100644 (file)
 
 #include "Cus428State.h"
 
+// MMC Command Codes.
+#define MMC_CMD_STOP                    0x01
+#define MMC_CMD_PLAY                    0x02
+#define MMC_CMD_DEFERRED_PLAY           0x03
+#define MMC_CMD_FAST_FORWARD            0x04
+#define MMC_CMD_REWIND                  0x05
+#define MMC_CMD_RECORD_STROBE           0x06
+#define MMC_CMD_RECORD_EXIT             0x07
+#define MMC_CMD_RECORD_PAUSE            0x08
+#define MMC_CMD_PAUSE                   0x09
+#define MMC_CMD_EJECT                   0x0a
+#define MMC_CMD_CHASE                   0x0b
+#define MMC_CMD_COMMAND_ERROR_RESET     0x0c
+#define MMC_CMD_MMC_RESET               0x0d
+#define MMC_CMD_JOG_START               0x20
+#define MMC_CMD_JOG_STOP                0x21
+#define MMC_CMD_WRITE                   0x40
+#define MMC_CMD_MASKED_WRITE            0x41
+#define MMC_CMD_READ                    0x42
+#define MMC_CMD_UPDATE                  0x43
+#define MMC_CMD_LOCATE                  0x44
+#define MMC_CMD_VARIABLE_PLAY           0x45
+#define MMC_CMD_SEARCH                  0x46
+#define MMC_CMD_SHUTTLE                 0x47
+#define MMC_CMD_STEP                    0x48
+#define MMC_CMD_ASSIGN_SYSTEM_MASTER    0x49
+#define MMC_CMD_GENERATOR_COMMAND       0x4a
+#define MMC_CMD_MTC_COMMAND             0x4b
+#define MMC_CMD_MOVE                    0x4c
+#define MMC_CMD_ADD                     0x4d
+#define MMC_CMD_SUBTRACT                0x4e
+#define MMC_CMD_DROP_FRAME_ADJUST       0x4f
+#define MMC_CMD_PROCEDURE               0x50
+#define MMC_CMD_EVENT                   0x51
+#define MMC_CMD_GROUP                   0x52
+#define MMC_CMD_COMMAND_SEGMENT         0x53
+#define MMC_CMD_DEFERRED_VARIABLE_PLAY  0x54
+#define MMC_CMD_RECORD_STROBE_VARIABLE  0x55
+#define MMC_CMD_WAIT                    0x7c
+#define MMC_CMD_RESUME                  0x7f
+
+
 class Cus428Midi {
  public:
        Cus428Midi():
@@ -30,9 +72,9 @@ class Cus428Midi {
                        snd_seq_set_client_name(Seq, "US-428");
                        Err = snd_seq_create_simple_port(Seq, "Controls",
                                                         SND_SEQ_PORT_CAP_READ
-                                                        //|SND_SEQ_PORT_CAP_WRITE      FIXME: Next Step is to make Lights switchable
+                                                        |SND_SEQ_PORT_CAP_WRITE
                                                         |SND_SEQ_PORT_CAP_SUBS_READ
-                                                        /*|SND_SEQ_PORT_CAP_SUBS_WRITE*/,
+                                                        |SND_SEQ_PORT_CAP_SUBS_WRITE,
                                                         SND_SEQ_PORT_TYPE_MIDI_GENERIC);
                        if (Err >= 0) {
                                Port = Err;
@@ -55,8 +97,16 @@ class Cus428Midi {
                return SendMidiControl(KnobParam[K - Cus428State::eK_RECORD], Down ? 0x7F : 0);
        }
 
- private:
+       // To parse and dispatch input MIDI events.
+       void ProcessMidiEvents();
+
+       // Send MMC command.
+       void SendMmcCommand(unsigned char MmcCmd, unsigned char *MmcData = 0, unsigned char MmcLen = 0);
+
+       // Made public for friendliness.
        snd_seq_t *Seq;
+
+ private:
        int Port;
        snd_seq_event_t Ev;
        int SubMitEvent(){
index d6bf76b9fff553adb6a34f0b85975e01e0676992..5e1ab0da87b67c213885e229a99a3b69ad87eb16 100644 (file)
@@ -25,7 +25,9 @@
 
 extern int verbose;
 
-
+// Differential wheel tracking constants.
+#define W_DELTA_MAX    0xff
+#define W_DELTA_MIN    (W_DELTA_MAX >> 1)
 
 void us428_lights::init_us428_lights()
 {
@@ -71,11 +73,14 @@ void Cus428State::SliderChangedTo(int S, unsigned char New)
                V.SetTo(S, New);
                if (S == eFaderM || !LightIs(eL_Mute0 + S))
                        SendVolume(V);
-       } else
-               Midi.SendMidiControl(0x40 + S, ((unsigned char*)us428_ctls)[S] / 2);
-
+       }
+       else SliderSend(S);
 }
 
+void Cus428State::SliderSend(int S)
+{
+       Midi.SendMidiControl(0x40 + S, ((unsigned char*)us428_ctls)[S] / 2);
+}
 
 void Cus428State::KnobChangedTo(eKnobs K, bool V)
 {
@@ -103,6 +108,73 @@ void Cus428State::KnobChangedTo(eKnobs K, bool V)
                break;
        default:
                switch (K) {
+               case eK_STOP:
+                       if (verbose > 1)
+                               printf("Knob STOP now %i\n", V);
+                       if (V) TransportToggle(T_STOP);
+                       Midi.SendMidiControl(K, V);
+                       break;
+               case eK_PLAY:
+                       if (verbose > 1)
+                               printf("Knob PLAY now %i", V);
+                       if (V) TransportToggle(T_PLAY);
+                       if (verbose > 1)
+                               printf(" Light is %i\n", LightIs(eL_Play));
+                       Midi.SendMidiControl(K, V);
+                       break;
+               case eK_REW:
+                       if (verbose > 1)
+                               printf("Knob REW now %i", V);
+                       if (V) TransportToggle(T_REW);
+                       if (verbose > 1)
+                               printf(" Light is %i\n", LightIs(eL_Rew));
+                       Midi.SendMidiControl(K, V);
+                       break;
+               case eK_FFWD:
+                       if (verbose > 1)
+                               printf("Knob FFWD now %i", V);
+                       if (V) TransportToggle(T_F_FWD);
+                       if (verbose > 1)
+                               printf(" Light is %i\n", LightIs(eL_FFwd));
+                       Midi.SendMidiControl(K, V);
+                       break;
+               case eK_RECORD:
+                       if (verbose > 1)
+                               printf("Knob RECORD now %i", V);
+                       if (V) TransportToggle(T_RECORD);
+                       if (verbose > 1)
+                               printf(" Light is %i\n", LightIs(eL_Record));
+                       Midi.SendMidiControl(K, V);
+                       break;
+               case eK_SET:
+                       if (verbose > 1)
+                               printf("Knob SET now %i", V);
+                       bSetLocate = V;
+                       break;
+               case eK_LOCATE_L:
+                       if (verbose > 1)
+                               printf("Knob LOCATE_L now %i", V);
+                       if (V) {
+                               if (bSetLocate)
+                                       aWheel_L = aWheel;
+                               else {
+                                       aWheel = aWheel_L;
+                                       LocateSend();
+                               }
+                       }
+                       break;
+               case eK_LOCATE_R:
+                       if (verbose > 1)
+                               printf("Knob LOCATE_R now %i", V);
+                       if (V) {
+                               if (bSetLocate)
+                                       aWheel_R = aWheel;
+                               else {
+                                       aWheel = aWheel_R;
+                                       LocateSend();
+                               }
+                       }
+                       break;
                case eK_InputMonitor:
                        if (verbose > 1)
                                printf("Knob InputMonitor now %i", V);
@@ -163,7 +235,166 @@ void Cus428State::WheelChangedTo(E_In84 W, char Diff)
                break;
        case eWheel:
                Param = 0x60;
+               // Update the absolute wheel position.
+               WheelDelta((int) ((unsigned char*) us428_ctls)[W]);
+               LocateSend();
                break;
        }
        Midi.SendMidiControl(Param, ((unsigned char*)us428_ctls)[W]);
 }
+
+
+// Convert time-code (hh:mm:ss:ff:fr) into absolute wheel position.
+void Cus428State::LocateWheel ( unsigned char *tc )
+{
+#if 0
+       aWheel  = (60 * 60 * 30) * (int) tc[0]          // hh - hours    [0..23]
+                       + (     60 * 30) * (int) tc[1]          // mm - minutes  [0..59]
+                       + (          30) * (int) tc[2]          // ss - seconds  [0..59]
+                       +                  (int) tc[3];         // ff - frames   [0..29]
+#else
+       aWheel  = (60 * 60 * 3) * (int) tc[0]           // hh - hours    [0..23]
+                       + (     60 * 3) * (int) tc[1]           // mm - minutes  [0..59]
+                       + (          3) * (int) tc[2]           // ss - seconds  [0..59]
+                       +                 (int) tc[3] / 10;     // ff - frames   [0..29]
+#endif
+}
+
+
+// Convert absolute wheel position into time-code (hh:mm:ss:ff:fr)
+void Cus428State::WheelTimecode ( unsigned char *tc )
+{
+       int W = aWheel;
+#if 0
+       tc[0] = W / (60 * 60 * 30); W -= (60 * 60 * 30) * (int) tc[0];
+       tc[1] = W / (     60 * 30); W -= (     60 * 30) * (int) tc[1];
+       tc[2] = W / (          30); W -= (          30) * (int) tc[2];
+       tc[3] = W;
+       tc[4] = 0;
+#else
+       tc[0] = W / (60 * 60 * 3); W -= (60 * 60 * 3) * (int) tc[0];
+       tc[1] = W / (     60 * 3); W -= (     60 * 3) * (int) tc[1];
+       tc[2] = W / (          3); W -= (          3) * (int) tc[2];
+       tc[3] = W * 10;
+       tc[4] = 0;
+#endif
+}
+
+
+// Get the wheel differential.
+void Cus428State::WheelDelta ( int W )
+{
+       // Compute the wheel differential.
+       int dW = W - W0;
+       if (dW > 0 && dW > +W_DELTA_MIN)
+               dW -= W_DELTA_MAX;
+       else
+       if (dW < 0 && dW < -W_DELTA_MIN)
+               dW += W_DELTA_MAX;
+
+       W0 = W;
+       aWheel += dW;
+
+       // Can't be less than zero.
+       if (aWheel < 0)
+               aWheel = 0;
+}
+
+
+// Send the MMC wheel locate command...
+void Cus428State::LocateSend ()
+{
+       unsigned char MmcData[6];
+       // Timecode's embedded on MMC command.
+       MmcData[0] = 0x01;
+       WheelTimecode(&MmcData[1]);
+       // Send the MMC locate command...
+       Midi.SendMmcCommand(MMC_CMD_LOCATE, MmcData, sizeof(MmcData));
+}
+
+
+// Toggle application transport state.
+void Cus428State::TransportToggle ( unsigned char T )
+{
+       switch (T) {
+       case T_PLAY:
+               if (uTransport & T_PLAY) {
+                       uTransport = T_STOP;
+                       Midi.SendMmcCommand(MMC_CMD_STOP);
+               } else {
+                   uTransport &= T_RECORD;
+                       uTransport |= T_PLAY;
+                       Midi.SendMmcCommand(MMC_CMD_PLAY);
+               }
+               break;
+       case T_RECORD:
+               if (uTransport & T_RECORD) {
+                       uTransport &= ~T_RECORD;
+                       Midi.SendMmcCommand(MMC_CMD_RECORD_EXIT);
+               } else {
+                   uTransport &= T_PLAY;
+                       uTransport |= T_RECORD;
+                       Midi.SendMmcCommand(uTransport & T_PLAY ? MMC_CMD_RECORD_STROBE : MMC_CMD_RECORD_PAUSE);
+               }
+               break;
+       default:
+               if (uTransport & T) {
+                       uTransport = T_STOP;
+               } else {
+                       uTransport = T;
+               }
+               if (uTransport & T_STOP)
+                       Midi.SendMmcCommand(MMC_CMD_STOP);
+               if (uTransport & T_REW)
+                       Midi.SendMmcCommand(MMC_CMD_REWIND);
+               if (uTransport & T_F_FWD)
+                       Midi.SendMmcCommand(MMC_CMD_FAST_FORWARD);
+               break;
+       }
+
+       TransportSend();
+}
+
+
+// Set application transport state.
+void Cus428State::TransportSet ( unsigned char T, bool V )
+{
+       if (V) {
+               if (T == T_RECORD) {
+                       uTransport |= T_RECORD;
+               } else {
+                       uTransport  = T;
+               }
+       } else {
+               if (T == T_RECORD) {
+                       uTransport &= ~T_RECORD;
+               } else {
+                       uTransport  = T_STOP;
+               }
+       }
+
+       TransportSend();
+}
+
+// Update transport lights.
+void Cus428State::TransportSend()
+{
+       LightSet(eL_Play,   (uTransport & T_PLAY));
+       LightSet(eL_Record, (uTransport & T_RECORD));
+       LightSet(eL_Rew,    (uTransport & T_REW));
+       LightSet(eL_FFwd,   (uTransport & T_F_FWD));
+       LightSend();
+}
+
+// Reset MMC state.
+void Cus428State::MmcReset()
+{
+       W0 = 0;
+       aWheel = aWheel_L = aWheel_R = 0;
+       bSetLocate = false;
+       uTransport = 0;
+
+       TransportSend();
+       LocateSend();
+}
+
index c2eb01eaa7f299313c01b8bd2fb8835900c10c6c..93ff0c45f084118e69ae82e95cfeb2aac462b015 100644 (file)
@@ -32,6 +32,12 @@ class Cus428State: public us428_lights{
                ,SelectInputMonitor(0)
                ,Select(0)
                ,us428_ctls(0)
+               ,W0(0)
+               ,aWheel(0)
+               ,aWheel_L(0)
+               ,aWheel_R(0)
+               ,bSetLocate(false)
+               ,uTransport(0)
                {
                        init_us428_lights();
                        for (int v = 0; v < 5; ++v) {
@@ -79,25 +85,52 @@ class Cus428State: public us428_lights{
        void InitDevice(void);
        void KnobChangedTo(eKnobs K, bool V);
        void SliderChangedTo(int S, unsigned char New);
+       void SliderSend(int S);
        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:
+       // Update the LED lights state.
        int LightSend();
+       // Time-code (hh:mm:ss:ff:fr) to/from absolute wheel position converters.
+       void LocateWheel(unsigned char *tc);
+       void LocateSend();
+       // Set basic application transport state.
+       void TransportToggle(unsigned char T);
+       void TransportSet(unsigned char T, bool V);
+       void TransportSend();
+       // Reset internal MMC state.
+       void MmcReset();
+ private:
        void SendVolume(usX2Y_volume &V);
        struct us428ctls_sharedmem* us428ctls_sharedmem;
        bool   StateInputMonitor() {
                return  LightIs(eL_InputMonitor);
        }
+       // Set the wheel differential.
+       void WheelDelta(int W);
+       // Get the curent wheel timecode.
+       void WheelTimecode(unsigned char *tc);
+
        usX2Y_volume_t  Volume[5];
        char            MuteInputMonitor,
                        Mute,
                        SelectInputMonitor,
                        Select;
        Cus428_ctls     *us428_ctls;
+       // Differential wheel tracking.
+       int W0;
+       // Some way to convert wheel (absolute) position into hh:mm:ss:ff:fr
+       int aWheel;
+       // SET L/R points.
+       int aWheel_L;
+       int aWheel_R;
+       // SET knob state.
+       bool bSetLocate;
+       // Last/current transport state.
+       unsigned char uTransport;
 };
 
 extern Cus428State* OneState;
index 628bd2025fc7cf69a6a4a1401b3017d7cad403c3..d4da3fdfa9f97b4097a17135cf0f44ae573a0ffd 100644 (file)
@@ -1,5 +1,5 @@
 AC_INIT(us428control.cc)
-AM_INIT_AUTOMAKE(us428control, 0.4.1)
+AM_INIT_AUTOMAKE(us428control, 0.4.2)
 AC_PROG_CXX
 AC_PROG_INSTALL
 AC_HEADER_STDC
index 28b856f8ab77b3402dd9b7ae0630bdbf748f88b2..e826ec48ba20106de9f1be05fc5b94720dfdcf4b 100644 (file)
@@ -89,7 +89,8 @@ int US428Control(const char* DevName)
        int                     err;
        unsigned int            idx, dsps, loaded;
        us428ctls_sharedmem_t   *us428ctls_sharedmem;
-       struct pollfd           pfds;
+       struct pollfd *pfds;
+       int npfd, pollrc;
 
        if ((err = snd_hwdep_open(&hw, DevName, O_RDWR)) < 0) {
                error("cannot open hwdep %s\n", DevName);
@@ -101,39 +102,51 @@ int US428Control(const char* DevName)
                snd_hwdep_close(hw);
                return -ENODEV;
        }
-       snd_hwdep_poll_descriptors(hw, &pfds, 1);
-       us428ctls_sharedmem = (us428ctls_sharedmem_t*)mmap(NULL, sizeof(us428ctls_sharedmem_t), PROT_READ|PROT_WRITE, MAP_SHARED, pfds.fd, 0);
+
+       Midi.CreatePorts();
+
+       npfd = snd_seq_poll_descriptors_count(Midi.Seq, POLLIN) + 1;
+       pfds = (struct pollfd *) alloca(npfd * sizeof(struct pollfd));
+       snd_hwdep_poll_descriptors(hw, &pfds[0], 1);
+       snd_seq_poll_descriptors(Midi.Seq, &pfds[1], npfd - 1, POLLIN);
+
+       us428ctls_sharedmem = (us428ctls_sharedmem_t *) mmap(NULL, sizeof(us428ctls_sharedmem_t), PROT_READ|PROT_WRITE, MAP_SHARED, pfds[0].fd, 0);
        if (us428ctls_sharedmem == MAP_FAILED) {
                perror("mmap failed:");
+               snd_hwdep_close(hw);
                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))
-                       printf("poll returned 0x%X\n", pfds.revents);
-               if (pfds.revents & (POLLERR|POLLHUP))
-                       return -ENXIO;
-               int Last = us428ctls_sharedmem->CtlSnapShotLast;
-               if (verbose > 1)
-                       printf("Last is %i\n", Last);
-               while (us428ctls_sharedmem->CtlSnapShotRed != Last) {
-                       static Cus428_ctls *Red = 0;
-                       int Read = us428ctls_sharedmem->CtlSnapShotRed + 1;
-                       if (Read >= N_us428_ctl_BUFS || Read < 0)
-                               Read = 0;
-                       Cus428_ctls* PCtlSnapShot = ((Cus428_ctls*)(us428ctls_sharedmem->CtlSnapShot)) + Read;
-                       int DiffAt = us428ctls_sharedmem->CtlSnapShotDiffersAt[Read];
+
+       while ((pollrc = poll(pfds, npfd, 60000)) >= 0) {
+               if (pfds[0].revents) {
+                       if (verbose > 1 || pfds[0].revents & (POLLERR|POLLHUP))
+                               printf("poll returned 0x%X\n", pfds[0].revents);
+                       if (pfds[0].revents & (POLLERR|POLLHUP))
+                               return -ENXIO;
+                       int Last = us428ctls_sharedmem->CtlSnapShotLast;
                        if (verbose > 1)
-                               PCtlSnapShot->dump(DiffAt);
-                       PCtlSnapShot->analyse(Red, DiffAt);
-                       Red = PCtlSnapShot;
-                       us428ctls_sharedmem->CtlSnapShotRed = Read;
+                               printf("Last is %i\n", Last);
+                       while (us428ctls_sharedmem->CtlSnapShotRed != Last) {
+                               static Cus428_ctls *Red = 0;
+                               int Read = us428ctls_sharedmem->CtlSnapShotRed + 1;
+                               if (Read >= N_us428_ctl_BUFS || Read < 0)
+                                       Read = 0;
+                               Cus428_ctls* PCtlSnapShot = ((Cus428_ctls*)(us428ctls_sharedmem->CtlSnapShot)) + Read;
+                               int DiffAt = us428ctls_sharedmem->CtlSnapShotDiffersAt[Read];
+                               if (verbose > 1)
+                                       PCtlSnapShot->dump(DiffAt);
+                               PCtlSnapShot->analyse(Red, DiffAt);
+                               Red = PCtlSnapShot;
+                               us428ctls_sharedmem->CtlSnapShotRed = Read;
+                       }
                }
+               else if (pollrc > 0) Midi.ProcessMidiEvents();
        }
+
+       return pollrc;
 }
 
 int main (int argc, char *argv[])
@@ -186,7 +199,7 @@ int main (int argc, char *argv[])
 
        /* probe the all cards */
        for (c = 0; c < SND_CARDS; c++) {
-               verbose--;
+       //      verbose--;
                sprintf(name, "hw:%d", c);
                if (! US428Control(name))
                        card = c;
index 0b65a29758d263bbb84da7f563ef8b1630b692c8..d3486692cc1fe69d2badc2e25ef0f218be86191c 100644 (file)
@@ -148,8 +148,17 @@ struct us428_lights{
        public:
        enum eLight{
                eL_Select0 = 0,
+               eL_Rec0 = 8,
                eL_Mute0 = 16,
-               eL_InputMonitor = 25
+               eL_Solo = 24,
+               eL_InputMonitor = 25,
+               eL_BankL = 26,
+               eL_BankR = 27,
+               eL_Rew = 28,
+               eL_FFwd = 29,
+               eL_Play = 30,
+               eL_Record = 31,
+               eL_Null
        };
        bool LightIs(int L){
                return Light[L / 8].Value & (1 << (L % 8));