2 Copyright (C) 2000 Paul Barton-Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "timecode/time.h"
26 #include "pbd/error.h"
28 #include "midi++/mmc.h"
29 #include "midi++/port.h"
30 #include "midi++/jack_midi_port.h"
31 #include "midi++/parser.h"
32 #include "midi++/manager.h"
38 static std::map<int,string> mmc_cmd_map;
39 static void build_mmc_cmd_map ()
41 pair<int,string> newpair;
44 newpair.second = "Stop";
45 mmc_cmd_map.insert (newpair);
48 newpair.second = "Play";
49 mmc_cmd_map.insert (newpair);
52 newpair.second = "DeferredPlay";
53 mmc_cmd_map.insert (newpair);
56 newpair.second = "FastForward";
57 mmc_cmd_map.insert (newpair);
60 newpair.second = "Rewind";
61 mmc_cmd_map.insert (newpair);
64 newpair.second = "RecordStrobe";
65 mmc_cmd_map.insert (newpair);
68 newpair.second = "RecordExit";
69 mmc_cmd_map.insert (newpair);
72 newpair.second = "RecordPause";
73 mmc_cmd_map.insert (newpair);
76 newpair.second = "Pause";
77 mmc_cmd_map.insert (newpair);
80 newpair.second = "Eject";
81 mmc_cmd_map.insert (newpair);
84 newpair.second = "Chase";
85 mmc_cmd_map.insert (newpair);
88 newpair.second = "CommandErrorReset";
89 mmc_cmd_map.insert (newpair);
92 newpair.second = "MmcReset";
93 mmc_cmd_map.insert (newpair);
96 newpair.second = "Illegal Mackie Jog Start";
97 mmc_cmd_map.insert (newpair);
100 newpair.second = "Illegal Mackie Jog Stop";
101 mmc_cmd_map.insert (newpair);
103 newpair.first = 0x40;
104 newpair.second = "Write";
105 mmc_cmd_map.insert (newpair);
107 newpair.first = 0x41;
108 newpair.second = "MaskedWrite";
109 mmc_cmd_map.insert (newpair);
111 newpair.first = 0x42;
112 newpair.second = "Read";
113 mmc_cmd_map.insert (newpair);
115 newpair.first = 0x43;
116 newpair.second = "Update";
117 mmc_cmd_map.insert (newpair);
119 newpair.first = 0x44;
120 newpair.second = "Locate";
121 mmc_cmd_map.insert (newpair);
123 newpair.first = 0x45;
124 newpair.second = "VariablePlay";
125 mmc_cmd_map.insert (newpair);
127 newpair.first = 0x46;
128 newpair.second = "Search";
129 mmc_cmd_map.insert (newpair);
131 newpair.first = 0x47;
132 newpair.second = "Shuttle";
133 mmc_cmd_map.insert (newpair);
135 newpair.first = 0x48;
136 newpair.second = "Step";
137 mmc_cmd_map.insert (newpair);
139 newpair.first = 0x49;
140 newpair.second = "AssignSystemMaster";
141 mmc_cmd_map.insert (newpair);
143 newpair.first = 0x4A;
144 newpair.second = "GeneratorCommand";
145 mmc_cmd_map.insert (newpair);
147 newpair.first = 0x4B;
148 newpair.second = "MtcCommand";
149 mmc_cmd_map.insert (newpair);
151 newpair.first = 0x4C;
152 newpair.second = "Move";
153 mmc_cmd_map.insert (newpair);
155 newpair.first = 0x4D;
156 newpair.second = "Add";
157 mmc_cmd_map.insert (newpair);
159 newpair.first = 0x4E;
160 newpair.second = "Subtract";
161 mmc_cmd_map.insert (newpair);
163 newpair.first = 0x4F;
164 newpair.second = "DropFrameAdjust";
165 mmc_cmd_map.insert (newpair);
167 newpair.first = 0x50;
168 newpair.second = "Procedure";
169 mmc_cmd_map.insert (newpair);
171 newpair.first = 0x51;
172 newpair.second = "Event";
173 mmc_cmd_map.insert (newpair);
175 newpair.first = 0x52;
176 newpair.second = "Group";
177 mmc_cmd_map.insert (newpair);
179 newpair.first = 0x53;
180 newpair.second = "CommandSegment";
181 mmc_cmd_map.insert (newpair);
183 newpair.first = 0x54;
184 newpair.second = "DeferredVariablePlay";
185 mmc_cmd_map.insert (newpair);
187 newpair.first = 0x55;
188 newpair.second = "RecordStrobeVariable";
189 mmc_cmd_map.insert (newpair);
191 newpair.first = 0x7C;
192 newpair.second = "Wait";
193 mmc_cmd_map.insert (newpair);
195 newpair.first = 0x7F;
196 newpair.second = "Resume";
197 mmc_cmd_map.insert (newpair);
201 MachineControl::MachineControl (Manager* m, ARDOUR::PortEngine& pengine)
203 build_mmc_cmd_map ();
205 _receive_device_id = 0x7f;
206 _send_device_id = 0x7f;
208 _input_port = m->add_port (new JackMIDIPort ("MMC in", Port::IsInput, pengine));
209 _output_port = m->add_port (new JackMIDIPort ("MMC out", Port::IsOutput, pengine));
211 _input_port->parser()->mmc.connect_same_thread (port_connections, boost::bind (&MachineControl::process_mmc_message, this, _1, _2, _3));
212 _input_port->parser()->start.connect_same_thread (port_connections, boost::bind (&MachineControl::spp_start, this));
213 _input_port->parser()->contineu.connect_same_thread (port_connections, boost::bind (&MachineControl::spp_continue, this));
214 _input_port->parser()->stop.connect_same_thread (port_connections, boost::bind (&MachineControl::spp_stop, this));
218 MachineControl::set_receive_device_id (byte id)
220 _receive_device_id = id & 0x7f;
224 MachineControl::set_send_device_id (byte id)
226 _send_device_id = id & 0x7f;
230 MachineControl::is_mmc (byte *sysex_buf, size_t len)
232 if (len < 4 || len > 48) {
236 if (sysex_buf[1] != 0x7f) {
240 if (sysex_buf[3] != 0x6 && /* MMC Command */
241 sysex_buf[3] != 0x7) { /* MMC Response */
249 MachineControl::process_mmc_message (Parser &, byte *msg, size_t len)
255 /* Reject if its not for us. 0x7f is the "all-call" device ID */
257 /* msg[0] = 0x7f (MMC sysex ID(
259 msg[2] = 0x6 (MMC command) or 0x7 (MMC response)
260 msg[3] = MMC command code
261 msg[4] = (typically) byte count for following part of command
265 cerr << "*** me = " << (int) _receive_device_id << " MMC message: len = " << len << "\n\t";
266 for (size_t i = 0; i < len; i++) {
267 cerr << hex << (int) msg[i] << dec << ' ';
272 if (msg[1] != 0x7f && msg[1] != _receive_device_id) {
283 /* this works for all non-single-byte "counted"
284 commands. we set it to 1 for the exceptions.
287 std::map<int,string>::iterator x = mmc_cmd_map.find ((int)mmc_msg[0]);
288 string cmdname = "unknown";
290 if (x != mmc_cmd_map.end()) {
291 cmdname = (*x).second;
295 cerr << "+++ MMC type "
299 << " \"" << cmdname << "\" "
306 /* SINGLE-BYTE, UNCOUNTED COMMANDS */
318 case cmdDeferredPlay:
319 DeferredPlay (*this);
333 case cmdRecordStrobe:
334 RecordStrobe (*this);
363 case cmdCommandErrorReset:
364 CommandErrorReset (*this);
373 case cmdIllegalMackieJogStart:
378 case cmdIllegalMackieJogStop:
383 /* END OF SINGLE-BYTE, UNCOUNTED COMMANDS */
386 do_masked_write (mmc_msg, len);
390 do_locate (mmc_msg, len);
394 do_shuttle (mmc_msg, len);
398 do_step (mmc_msg, len);
404 case cmdVariablePlay:
406 case cmdAssignSystemMaster:
407 case cmdGeneratorCommand:
412 case cmdDropFrameAdjust:
416 case cmdCommandSegment:
417 case cmdDeferredVariablePlay:
418 case cmdRecordStrobeVariable:
421 error << "MIDI::MachineControl: unimplemented MMC command "
422 << hex << (int) *mmc_msg << dec
428 error << "MIDI::MachineControl: unknown MMC command "
429 << hex << (int) *mmc_msg << dec
435 /* increase skiplen to cover the command byte and
436 count byte (if it existed).
440 skiplen = mmc_msg[1] + 2;
445 if (len <= skiplen) {
452 } while (len > 1); /* skip terminating EOX byte */
456 MachineControl::do_masked_write (byte *msg, size_t len)
458 /* return the number of bytes "consumed" */
460 int retval = msg[1] + 2; /* bytes following + 2 */
463 case 0x4f: /* Track Record Ready Status */
464 write_track_status (&msg[3], len - 3, msg[2]);
467 case 0x62: /* track mute */
468 write_track_status (&msg[3], len - 3, msg[2]);
472 warning << "MIDI::MachineControl: masked write to "
473 << hex << (int) msg[2] << dec
474 << " not implemented"
482 MachineControl::write_track_status (byte *msg, size_t /*len*/, byte reg)
487 /* Bits 0-4 of the first byte are for special tracks:
495 the format of the message (its an MMC Masked Write) is:
498 <count> byte count of following data
499 <name> byte value of the field being written
500 <byte #> byte number of target byte in the
501 bitmap being written to
502 <mask> ones in the mask indicate which bits will be changed
503 <data> new data for the byte being written
505 by the time this code is executing, msg[0] is the
506 byte number of the target byte. if its zero, we
507 are writing to a special byte in the standard
508 track bitmap, in which the first 5 bits are
509 special. hence the bits for tracks 1 + 2 are bits
510 5 and 6 of the first byte of the track
513 change track 1: msg[0] = 0; << first byte of track bitmap
514 msg[1] = 0100000; << binary: bit 5 set
516 change track 2: msg[0] = 0; << first byte of track bitmap
517 msg[1] = 1000000; << binary: bit 6 set
519 change track 3: msg[0] = 1; << second byte of track bitmap
520 msg[1] = 0000001; << binary: bit 0 set
522 the (msg[0] * 8) - 6 computation is an attempt to
523 extract the value of the first track: ie. the one
524 that would be indicated by bit 0 being set.
526 so, if msg[0] = 0, msg[1] = 0100000 (binary),
527 what happens is that base_track = -5, but by the
528 time we check the correct bit, n = 5, and so the
529 computed track for the status change is 0 (first
532 if msg[0] = 1, then the base track for any change is 2 (the third track), and so on.
535 /* XXX check needed to make sure we don't go outside the
536 supported number of tracks.
542 base_track = (msg[0] * 8) - 6;
545 for (n = 0; n < 7; n++) {
546 if (msg[1] & (1<<n)) {
548 /* Only touch tracks that have the "mask"
552 bool val = (msg[2] & (1<<n));
556 trackRecordStatus[base_track+n] = val;
557 TrackRecordStatusChange (*this, base_track+n, val);
561 trackMute[base_track+n] = val;
562 TrackMuteChange (*this, base_track+n, val);
571 MachineControl::do_locate (byte *msg, size_t /*msglen*/)
574 warning << "MIDI::MMC: locate [I/F] command not supported"
579 /* regular "target" locate command */
581 Locate (*this, &msg[3]);
586 MachineControl::do_step (byte *msg, size_t /*msglen*/)
588 int steps = msg[2] & 0x3f;
599 MachineControl::do_shuttle (byte *msg, size_t /*msglen*/)
616 left_shift = (sh & 0x38);
618 integral = ((sh & 0x7) << left_shift) | (sm >> (7 - left_shift));
619 fractional = ((sm << left_shift) << 7) | sl;
621 shuttle_speed = integral +
622 ((float)fractional / (1 << (14 - left_shift)));
624 Shuttle (*this, shuttle_speed, forward);
630 MachineControl::enable_send (bool yn)
635 /** Send a MMC command to a the MMC port.
639 MachineControl::send (MachineControlCommand const & c)
641 if (_output_port == 0 || !_enable_send) {
642 // cerr << "Not delivering MMC " << _mmc->port() << " - " << session_send_mmc << endl;
646 MIDI::byte buffer[32];
647 MIDI::byte* b = c.fill_buffer (this, buffer);
649 if (_output_port->midimsg (buffer, b - buffer, 0)) {
650 error << "MMC: cannot send command" << endmsg;
655 MachineControl::spp_start ()
657 SPPStart (); /* EMIT SIGNAL */
661 MachineControl::spp_continue ()
663 SPPContinue (); /* EMIT SIGNAL */
667 MachineControl::spp_stop ()
669 SPPStop (); /* EMIT SIGNAL */
672 MachineControlCommand::MachineControlCommand (MachineControl::Command c)
678 MachineControlCommand::MachineControlCommand (Timecode::Time t)
679 : _command (MachineControl::cmdLocate)
686 MachineControlCommand::fill_buffer (MachineControl* mmc, MIDI::byte* b) const
688 *b++ = 0xf0; // SysEx
689 *b++ = 0x7f; // Real-time SysEx ID for MMC
690 *b++ = mmc->send_device_id();
691 *b++ = 0x6; // MMC command
695 if (_command == MachineControl::cmdLocate) {
696 *b++ = 0x6; // byte count
697 *b++ = 0x1; // "TARGET" subcommand
699 *b++ = _time.minutes;
700 *b++ = _time.seconds;
702 *b++ = _time.subframes;