diff options
author | Taybin Rutkin <taybin@taybin.com> | 2005-05-13 20:47:18 +0000 |
---|---|---|
committer | Taybin Rutkin <taybin@taybin.com> | 2005-05-13 20:47:18 +0000 |
commit | d09f6b3016bacbc2871a8946cbb24ad705076509 (patch) | |
tree | f27312839c2a772cb2ce068a4f28b2449ad869df /libs/midi++2/mmc.cc |
Initial revision
git-svn-id: svn://localhost/trunk/ardour2@4 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/midi++2/mmc.cc')
-rw-r--r-- | libs/midi++2/mmc.cc | 577 |
1 files changed, 577 insertions, 0 deletions
diff --git a/libs/midi++2/mmc.cc b/libs/midi++2/mmc.cc new file mode 100644 index 0000000000..a0de774329 --- /dev/null +++ b/libs/midi++2/mmc.cc @@ -0,0 +1,577 @@ +/* + Copyright (C) 2000 Paul Barton-Davis + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id$ +*/ + +#include <map> + +#include <pbd/error.h> +#include <midi++/mmc.h> +#include <midi++/port.h> +#include <midi++/parser.h> + +using namespace std; +using namespace MIDI; + +static std::map<int,string> mmc_cmd_map; +static void build_mmc_cmd_map () +{ + pair<int,string> newpair; + + newpair.first = 0x1; + newpair.second = "Stop"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0x2; + newpair.second = "Play"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0x3; + newpair.second = "DeferredPlay"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0x4; + newpair.second = "FastForward"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0x5; + newpair.second = "Rewind"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0x6; + newpair.second = "RecordStrobe"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0x7; + newpair.second = "RecordExit"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0x8; + newpair.second = "RecordPause"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0x9; + newpair.second = "Pause"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0xA; + newpair.second = "Eject"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0xB; + newpair.second = "Chase"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0xC; + newpair.second = "CommandErrorReset"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0xD; + newpair.second = "MmcReset"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0x20; + newpair.second = "Illegal Mackie Jog Start"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0x21; + newpair.second = "Illegal Mackie Jog Stop"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0x40; + newpair.second = "Write"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0x41; + newpair.second = "MaskedWrite"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0x42; + newpair.second = "Read"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0x43; + newpair.second = "Update"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0x44; + newpair.second = "Locate"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0x45; + newpair.second = "VariablePlay"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0x46; + newpair.second = "Search"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0x47; + newpair.second = "Shuttle"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0x48; + newpair.second = "Step"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0x49; + newpair.second = "AssignSystemMaster"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0x4A; + newpair.second = "GeneratorCommand"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0x4B; + newpair.second = "MtcCommand"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0x4C; + newpair.second = "Move"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0x4D; + newpair.second = "Add"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0x4E; + newpair.second = "Subtract"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0x4F; + newpair.second = "DropFrameAdjust"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0x50; + newpair.second = "Procedure"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0x51; + newpair.second = "Event"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0x52; + newpair.second = "Group"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0x53; + newpair.second = "CommandSegment"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0x54; + newpair.second = "DeferredVariablePlay"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0x55; + newpair.second = "RecordStrobeVariable"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0x7C; + newpair.second = "Wait"; + mmc_cmd_map.insert (newpair); + + newpair.first = 0x7F; + newpair.second = "Resume"; + mmc_cmd_map.insert (newpair); +} + + +MachineControl::MachineControl (Port &p, float version, + CommandSignature &csig, + ResponseSignature &rsig) + + : _port (p) +{ + Parser *parser; + + build_mmc_cmd_map (); + + _device_id = 1; + + if ((parser = _port.input()) != 0) { + parser->mmc.connect + (mem_fun (*this, &MachineControl::process_mmc_message)); + } else { + warning << "MMC connected to a non-input port: useless!" + << endmsg; + } +} + +void +MachineControl::set_device_id (byte id) + +{ + _device_id = id & 0x7f; +} + +bool +MachineControl::is_mmc (byte *sysex_buf, size_t len) + +{ + if (len < 4 || len > 48) { + return false; + } + + if (sysex_buf[1] != 0x7f) { + return false; + } + + if (sysex_buf[3] != 0x6 && /* MMC Command */ + sysex_buf[3] != 0x7) { /* MMC Response */ + return false; + } + + return true; +} + +void +MachineControl::process_mmc_message (Parser &p, byte *msg, size_t len) + +{ + size_t skiplen; + byte *mmc_msg; + bool single_byte; + + /* Reject if its not for us. 0x7f is the "all-call" device ID */ + + /* msg[0] = 0x7f (MMC sysex ID( + msg[1] = device ID + msg[2] = 0x6 (MMC command) or 0x7 (MMC response) + msg[3] = MMC command code + msg[4] = (typically) byte count for following part of command + */ + +#if 0 + cerr << "*** MMC message: len = " << len << "\n\t"; + for (size_t i = 0; i < len; i++) { + cerr << hex << (int) msg[i] << dec << ' '; + } + cerr << endl; +#endif + + if (msg[1] != 0x7f && msg[1] != _device_id) { + return; + } + + mmc_msg = &msg[3]; + len -= 3; + + do { + + single_byte = false; + + /* this works for all non-single-byte "counted" + commands. we set it to 1 for the exceptions. + */ + + std::map<int,string>::iterator x = mmc_cmd_map.find ((int)mmc_msg[0]); + string cmdname = "unknown"; + + if (x != mmc_cmd_map.end()) { + cmdname = (*x).second; + } + +#if 0 + cerr << "+++ MMC type " + << hex + << ((int) *mmc_msg) + << dec + << " \"" << cmdname << "\" " + << " len = " << len + << endl; +#endif + + switch (*mmc_msg) { + + /* SINGLE-BYTE, UNCOUNTED COMMANDS */ + + case cmdStop: + Stop (*this); + single_byte = true; + break; + + case cmdPlay: + Play (*this); + single_byte = true; + break; + + case cmdDeferredPlay: + DeferredPlay (*this); + single_byte = true; + break; + + case cmdFastForward: + FastForward (*this); + single_byte = true; + break; + + case cmdRewind: + Rewind (*this); + single_byte = true; + break; + + case cmdRecordStrobe: + RecordStrobe (*this); + single_byte = true; + break; + + case cmdRecordExit: + RecordExit (*this); + single_byte = true; + break; + + case cmdRecordPause: + RecordPause (*this); + single_byte = true; + break; + + case cmdPause: + Pause (*this); + single_byte = true; + break; + + case cmdEject: + Eject (*this); + single_byte = true; + break; + + case cmdChase: + Chase (*this); + single_byte = true; + break; + + case cmdCommandErrorReset: + CommandErrorReset (*this); + single_byte = true; + break; + + case cmdMmcReset: + MmcReset (*this); + single_byte = true; + break; + + case cmdIllegalMackieJogStart: + JogStart (*this); + single_byte = true; + break; + + case cmdIllegalMackieJogStop: + JogStop (*this); + single_byte = true; + break; + + /* END OF SINGLE-BYTE, UNCOUNTED COMMANDS */ + + case cmdMaskedWrite: + do_masked_write (mmc_msg, len); + break; + + case cmdLocate: + do_locate (mmc_msg, len); + break; + + case cmdShuttle: + do_shuttle (mmc_msg, len); + break; + + case cmdStep: + do_step (mmc_msg, len); + break; + + case cmdWrite: + case cmdRead: + case cmdUpdate: + case cmdVariablePlay: + case cmdSearch: + case cmdAssignSystemMaster: + case cmdGeneratorCommand: + case cmdMtcCommand: + case cmdMove: + case cmdAdd: + case cmdSubtract: + case cmdDropFrameAdjust: + case cmdProcedure: + case cmdEvent: + case cmdGroup: + case cmdCommandSegment: + case cmdDeferredVariablePlay: + case cmdRecordStrobeVariable: + case cmdWait: + case cmdResume: + error << "MIDI::MachineControl: unimplemented MMC command " + << hex << (int) *mmc_msg << dec + << endmsg; + + break; + + default: + error << "MIDI::MachineControl: unknown MMC command " + << hex << (int) *mmc_msg << dec + << endmsg; + + break; + } + + /* increase skiplen to cover the command byte and + count byte (if it existed). + */ + + if (!single_byte) { + skiplen = mmc_msg[1] + 2; + } else { + skiplen = 1; + } + + if (len <= skiplen) { + break; + } + + mmc_msg += skiplen; + len -= skiplen; + + } while (len > 1); /* skip terminating EOX byte */ +} + +int +MachineControl::do_masked_write (byte *msg, size_t len) + +{ + /* return the number of bytes "consumed" */ + + int retval = msg[1] + 2; /* bytes following + 2 */ + + switch (msg[2]) { + case 0x4f: /* Track Record Ready Status */ + write_track_record_ready (&msg[3], len - 3); + break; + + default: + warning << "MIDI::MachineControl: masked write to " + << hex << (int) msg[2] << dec + << " not implemented" + << endmsg; + } + + return retval; +} + +void +MachineControl::write_track_record_ready (byte *msg, size_t len) + +{ + size_t n; + size_t base_track; + + /* Bits 0-4 of the first byte are for special tracks: + + bit 0: video + bit 1: reserved + bit 2: time code + bit 3: aux track a + bit 4: aux track b + + */ + + /* XXX check needed to make sure we don't go outside the + support number of tracks. + */ + + base_track = (msg[0] * 7) - 5; + + for (n = 0; n < 7; n++) { + if (msg[1] & (1<<n)) { + + /* Only touch tracks that have the "mask" + bit set. + */ + + if (msg[2] & (1<<n)) { + trackRecordStatus[base_track+n] = true; + TrackRecordStatusChange (*this, base_track+n, + true); + } else { + trackRecordStatus[base_track+n] = false; + TrackRecordStatusChange (*this, base_track+n, + false); + } + } + + } +} + +int +MachineControl::do_locate (byte *msg, size_t msglen) + +{ + if (msg[2] == 0) { + warning << "MIDI::MMC: locate [I/F] command not supported" + << endmsg; + return 0; + } + + /* regular "target" locate command */ + + Locate (*this, &msg[3]); + return 0; +} + +int +MachineControl::do_step (byte *msg, size_t msglen) +{ + int steps = msg[2] & 0x3f; + + if (msg[2] & 0x40) { + steps = -steps; + } + + Step (*this, steps); + return 0; +} + +int +MachineControl::do_shuttle (byte *msg, size_t msglen) + +{ + size_t forward; + byte sh = msg[2]; + byte sm = msg[3]; + byte sl = msg[4]; + size_t left_shift; + size_t integral; + size_t fractional; + float shuttle_speed; + + if (sh & (1<<6)) { + forward = false; + } else { + forward = true; + } + + left_shift = (sh & 0x38); + + integral = ((sh & 0x7) << left_shift) | (sm >> (7 - left_shift)); + fractional = ((sm << left_shift) << 7) | sl; + + shuttle_speed = integral + + ((float)fractional / (1 << (14 - left_shift))); + + Shuttle (*this, shuttle_speed, forward); + + return 0; +} + |