mirror of
https://github.com/alsa-project/alsa-tools.git
synced 2025-10-28 05:40:23 -04:00
- A new command line option indicates which interface model is actually present (-m us428|us224|mixxx) -- nb. the mixxx mode is actually orthogonal to the us428 and us224 ones, which are in turn both mutually exclusive, so that more than one -m option can be specified in the same command line, for compatibility sake; default to us428 mode, of course. - New BANK switching allows for mapping to a maximum of 32 (!) logical channel-tracks. This introduces effective BANK L/R button functionality. Under the default us428 mode it now offers a total of 4 switchable banks (or layers) for the available 8 fader-channels; while in the new us224 mode, one can switch across 8 banks of 4 fader-channels each. Each fader-channel maps sequentially (0-31) to a logical track in your DAW, when connected in a MMC closed-loop. This only applies when not in INPUT MONITOR mode. - SELECT, REC, MUTE and SOLO state LEDs/buttons/channel functionality are now split into INPUT MONITOR and BANK modes, so that each bank (layer) has its own state. INPUT MONITOR mode gets its own independent state, which is the only that affects the audio interface channel signal volume (via respective faders) through the internal hardware mixer -- nb. this special mode deals exclusively to channel/faders 0 and 1 (A/B) and eventually to 2 and 3 (C/D) which are only available on the US-428 and made accessible through modprobe'ing snd-usb-usx2y with nrpacks=1 and thus made usable via the special hwdep "rawusb" interface mode (ie. hw:N,2). - The new track-channel mapping gets effectively signaled through correspondent but rather experimental MMC MASKED WRITE sub-commands for RECORD, MUTE and SOLO arming. It is important to note that this late SOLO sub-command is just some MMC implementation mockup of mine, as I believe there's no support whatsoever for just that from the official MIDI MMC RP-013 document (which I don't even have access to date:) However, I've been prototyping around with this, to my own amusement and home-brew audio/MIDI sequencer, qtractor: http://qtractor.sourceforge.net - NULL fader switch LED is now switchable on/off, but not actually of any usefulness at this time ;) I have tried to maintain all previous functionality as it were. Of course I only tested this new stuff over my own US-224, for which it surely needs the '-m us224' command-line option. This is also proposedto be specified in a correspondent udev rule, for all this to work correctly OOTB for the US-224 at least. US-428 owners don't need to bother ;) From: Rui Nuno Capela <rncbc@rncbc.org>
258 lines
6 KiB
C++
258 lines
6 KiB
C++
/* -*- mode:C++; indent-tabs-mode:t; tab-width:8; c-basic-offset: 8 -*- */
|
|
/*
|
|
*
|
|
* Copyright (c) 2003 by Karsten Wiese <annabellesgarden@yahoo.de>
|
|
* Copyright (c) 2004-2007 by Rui Nuno Capela <rncbc@rncbc.org>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#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,
|
|
};
|
|
|
|
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.\n");
|
|
OneState->LocateWheel(&data[7]);
|
|
break;
|
|
case MMC_CMD_MASKED_WRITE:
|
|
if (verbose > 1)
|
|
fprintf(stderr, "MASKED WRITE.\n");
|
|
OneState->MaskedWrite(&data[6]);
|
|
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();
|
|
}
|