mirror of
https://github.com/alsa-project/alsa-tools.git
synced 2025-10-29 05:40:25 -04:00
Added MMC support by Rui Nuno Capela <rncbc@rncbc.org>
MMC support has been improved and transport LEDs is getting almost functional. Tascam control protocol sysex decoding is also complete (LEDs control mainly).
This commit is contained in:
parent
9615f45528
commit
5313c94163
7 changed files with 541 additions and 35 deletions
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,48 @@
|
|||
|
||||
#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(){
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue