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"
25 #include "timecode/bbt_time.h"
27 #include "pbd/error.h"
29 #include "midi++/mmc.h"
30 #include "midi++/port.h"
31 #include "midi++/parser.h"
33 #ifndef __INT_MAX__ // 'ssize_t' won't be defined yet
42 * As libtimecode is linked statically to libmidi++ this
43 * is necessary to pull in all the symbols from libtimecode
44 * so they are exported for other users of libtimecode.
46 double tmp = Timecode::BBT_Time::ticks_per_beat;
48 static std::map<int,string> mmc_cmd_map;
49 static void build_mmc_cmd_map ()
51 pair<int,string> newpair;
54 newpair.second = "Stop";
55 mmc_cmd_map.insert (newpair);
58 newpair.second = "Play";
59 mmc_cmd_map.insert (newpair);
62 newpair.second = "DeferredPlay";
63 mmc_cmd_map.insert (newpair);
66 newpair.second = "FastForward";
67 mmc_cmd_map.insert (newpair);
70 newpair.second = "Rewind";
71 mmc_cmd_map.insert (newpair);
74 newpair.second = "RecordStrobe";
75 mmc_cmd_map.insert (newpair);
78 newpair.second = "RecordExit";
79 mmc_cmd_map.insert (newpair);
82 newpair.second = "RecordPause";
83 mmc_cmd_map.insert (newpair);
86 newpair.second = "Pause";
87 mmc_cmd_map.insert (newpair);
90 newpair.second = "Eject";
91 mmc_cmd_map.insert (newpair);
94 newpair.second = "Chase";
95 mmc_cmd_map.insert (newpair);
98 newpair.second = "CommandErrorReset";
99 mmc_cmd_map.insert (newpair);
102 newpair.second = "MmcReset";
103 mmc_cmd_map.insert (newpair);
105 newpair.first = 0x20;
106 newpair.second = "Illegal Mackie Jog Start";
107 mmc_cmd_map.insert (newpair);
109 newpair.first = 0x21;
110 newpair.second = "Illegal Mackie Jog Stop";
111 mmc_cmd_map.insert (newpair);
113 newpair.first = 0x40;
114 newpair.second = "Write";
115 mmc_cmd_map.insert (newpair);
117 newpair.first = 0x41;
118 newpair.second = "MaskedWrite";
119 mmc_cmd_map.insert (newpair);
121 newpair.first = 0x42;
122 newpair.second = "Read";
123 mmc_cmd_map.insert (newpair);
125 newpair.first = 0x43;
126 newpair.second = "Update";
127 mmc_cmd_map.insert (newpair);
129 newpair.first = 0x44;
130 newpair.second = "Locate";
131 mmc_cmd_map.insert (newpair);
133 newpair.first = 0x45;
134 newpair.second = "VariablePlay";
135 mmc_cmd_map.insert (newpair);
137 newpair.first = 0x46;
138 newpair.second = "Search";
139 mmc_cmd_map.insert (newpair);
141 newpair.first = 0x47;
142 newpair.second = "Shuttle";
143 mmc_cmd_map.insert (newpair);
145 newpair.first = 0x48;
146 newpair.second = "Step";
147 mmc_cmd_map.insert (newpair);
149 newpair.first = 0x49;
150 newpair.second = "AssignSystemMaster";
151 mmc_cmd_map.insert (newpair);
153 newpair.first = 0x4A;
154 newpair.second = "GeneratorCommand";
155 mmc_cmd_map.insert (newpair);
157 newpair.first = 0x4B;
158 newpair.second = "MtcCommand";
159 mmc_cmd_map.insert (newpair);
161 newpair.first = 0x4C;
162 newpair.second = "Move";
163 mmc_cmd_map.insert (newpair);
165 newpair.first = 0x4D;
166 newpair.second = "Add";
167 mmc_cmd_map.insert (newpair);
169 newpair.first = 0x4E;
170 newpair.second = "Subtract";
171 mmc_cmd_map.insert (newpair);
173 newpair.first = 0x4F;
174 newpair.second = "DropFrameAdjust";
175 mmc_cmd_map.insert (newpair);
177 newpair.first = 0x50;
178 newpair.second = "Procedure";
179 mmc_cmd_map.insert (newpair);
181 newpair.first = 0x51;
182 newpair.second = "Event";
183 mmc_cmd_map.insert (newpair);
185 newpair.first = 0x52;
186 newpair.second = "Group";
187 mmc_cmd_map.insert (newpair);
189 newpair.first = 0x53;
190 newpair.second = "CommandSegment";
191 mmc_cmd_map.insert (newpair);
193 newpair.first = 0x54;
194 newpair.second = "DeferredVariablePlay";
195 mmc_cmd_map.insert (newpair);
197 newpair.first = 0x55;
198 newpair.second = "RecordStrobeVariable";
199 mmc_cmd_map.insert (newpair);
201 newpair.first = 0x7C;
202 newpair.second = "Wait";
203 mmc_cmd_map.insert (newpair);
205 newpair.first = 0x7F;
206 newpair.second = "Resume";
207 mmc_cmd_map.insert (newpair);
210 MachineControl::MachineControl ()
212 build_mmc_cmd_map ();
214 _receive_device_id = 0x7f;
215 _send_device_id = 0x7f;
219 MachineControl::set_ports (MIDI::Port* ip, MIDI::Port* op)
221 port_connections.drop_connections ();
226 _input_port->parser()->mmc.connect_same_thread (port_connections, boost::bind (&MachineControl::process_mmc_message, this, _1, _2, _3));
227 _input_port->parser()->start.connect_same_thread (port_connections, boost::bind (&MachineControl::spp_start, this));
228 _input_port->parser()->contineu.connect_same_thread (port_connections, boost::bind (&MachineControl::spp_continue, this));
229 _input_port->parser()->stop.connect_same_thread (port_connections, boost::bind (&MachineControl::spp_stop, this));
233 MachineControl::set_receive_device_id (MIDI::byte id)
235 _receive_device_id = id & 0x7f;
239 MachineControl::set_send_device_id (MIDI::byte id)
241 _send_device_id = id & 0x7f;
245 MachineControl::is_mmc (MIDI::byte *sysex_buf, size_t len)
247 if (len < 4 || len > 48) {
251 if (sysex_buf[1] != 0x7f) {
255 if (sysex_buf[3] != 0x6 && /* MMC Command */
256 sysex_buf[3] != 0x7) { /* MMC Response */
264 MachineControl::process_mmc_message (Parser &, MIDI::byte *msg, size_t len)
270 /* Reject if its not for us. 0x7f is the "all-call" device ID */
272 /* msg[0] = 0x7f (MMC sysex ID(
274 msg[2] = 0x6 (MMC command) or 0x7 (MMC response)
275 msg[3] = MMC command code
276 msg[4] = (typically) byte count for following part of command
280 cerr << "*** me = " << (int) _receive_device_id << " MMC message: len = " << len << "\n\t";
281 for (size_t i = 0; i < len; i++) {
282 cerr << hex << (int) msg[i] << dec << ' ';
287 if (_receive_device_id != 0x7f && msg[1] != 0x7f && msg[1] != _receive_device_id) {
298 /* this works for all non-single-byte "counted"
299 commands. we set it to 1 for the exceptions.
302 std::map<int,string>::iterator x = mmc_cmd_map.find ((int)mmc_msg[0]);
303 string cmdname = "unknown";
305 if (x != mmc_cmd_map.end()) {
306 cmdname = (*x).second;
310 cerr << "+++ MMC type "
314 << " \"" << cmdname << "\" "
321 /* SINGLE-BYTE, UNCOUNTED COMMANDS */
333 case cmdDeferredPlay:
334 DeferredPlay (*this);
348 case cmdRecordStrobe:
349 RecordStrobe (*this);
378 case cmdCommandErrorReset:
379 CommandErrorReset (*this);
388 case cmdIllegalMackieJogStart:
393 case cmdIllegalMackieJogStop:
398 /* END OF SINGLE-BYTE, UNCOUNTED COMMANDS */
401 do_masked_write (mmc_msg, len);
405 do_locate (mmc_msg, len);
409 do_shuttle (mmc_msg, len);
413 do_step (mmc_msg, len);
419 case cmdVariablePlay:
421 case cmdAssignSystemMaster:
422 case cmdGeneratorCommand:
427 case cmdDropFrameAdjust:
431 case cmdCommandSegment:
432 case cmdDeferredVariablePlay:
433 case cmdRecordStrobeVariable:
436 error << "MIDI::MachineControl: unimplemented MMC command "
437 << hex << (int) *mmc_msg << dec
443 error << "MIDI::MachineControl: unknown MMC command "
444 << hex << (int) *mmc_msg << dec
450 /* increase skiplen to cover the command byte and
451 count byte (if it existed).
455 skiplen = mmc_msg[1] + 2;
460 if (len <= skiplen) {
467 } while (len > 1); /* skip terminating EOX byte */
471 MachineControl::do_masked_write (MIDI::byte *msg, size_t len)
473 /* return the number of bytes "consumed" */
475 int retval = msg[1] + 2; /* bytes following + 2 */
478 case 0x4f: /* Track Record Ready Status */
479 write_track_status (&msg[3], len - 3, msg[2]);
482 case 0x62: /* track mute */
483 write_track_status (&msg[3], len - 3, msg[2]);
487 warning << "MIDI::MachineControl: masked write to "
488 << hex << (int) msg[2] << dec
489 << " not implemented"
497 MachineControl::write_track_status (MIDI::byte *msg, size_t /*len*/, MIDI::byte reg)
502 /* Bits 0-4 of the first byte are for special tracks:
510 the format of the message (its an MMC Masked Write) is:
513 <count> byte count of following data
514 <name> byte value of the field being written
515 <byte #> byte number of target byte in the
516 bitmap being written to
517 <mask> ones in the mask indicate which bits will be changed
518 <data> new data for the byte being written
520 by the time this code is executing, msg[0] is the
521 byte number of the target byte. if its zero, we
522 are writing to a special byte in the standard
523 track bitmap, in which the first 5 bits are
524 special. hence the bits for tracks 1 + 2 are bits
525 5 and 6 of the first byte of the track
528 change track 1: msg[0] = 0; << first byte of track bitmap
529 msg[1] = 0100000; << binary: bit 5 set
531 change track 2: msg[0] = 0; << first byte of track bitmap
532 msg[1] = 1000000; << binary: bit 6 set
534 change track 3: msg[0] = 1; << second byte of track bitmap
535 msg[1] = 0000001; << binary: bit 0 set
537 the (msg[0] * 8) - 6 computation is an attempt to
538 extract the value of the first track: ie. the one
539 that would be indicated by bit 0 being set.
541 so, if msg[0] = 0, msg[1] = 0100000 (binary),
542 what happens is that base_track = -5, but by the
543 time we check the correct bit, n = 5, and so the
544 computed track for the status change is 0 (first
547 if msg[0] = 1, then the base track for any change is 2 (the third track), and so on.
550 /* XXX check needed to make sure we don't go outside the
551 supported number of tracks.
557 base_track = (msg[0] * 8) - 6;
560 for (n = 0; n < 7; n++) {
561 if (msg[1] & (1<<n)) {
563 /* Only touch tracks that have the "mask"
567 bool val = (msg[2] & (1<<n));
571 trackRecordStatus[base_track+n] = val;
572 TrackRecordStatusChange (*this, base_track+n, val);
576 trackMute[base_track+n] = val;
577 TrackMuteChange (*this, base_track+n, val);
586 MachineControl::do_locate (MIDI::byte *msg, size_t /*msglen*/)
589 warning << "MIDI::MMC: locate [I/F] command not supported"
594 /* regular "target" locate command */
596 Locate (*this, &msg[3]);
601 MachineControl::do_step (MIDI::byte *msg, size_t /*msglen*/)
603 int steps = msg[2] & 0x3f;
614 MachineControl::do_shuttle (MIDI::byte *msg, size_t /*msglen*/)
631 left_shift = (sh & 0x38);
633 integral = ((sh & 0x7) << left_shift) | (sm >> (7 - left_shift));
634 fractional = ((sm << left_shift) << 7) | sl;
636 shuttle_speed = integral +
637 ((float)fractional / (1 << (14 - left_shift)));
639 Shuttle (*this, shuttle_speed, forward);
645 MachineControl::enable_send (bool yn)
650 /** Send a MMC command to a the MMC port.
654 MachineControl::send (MachineControlCommand const & c, timestamp_t when)
656 if (_output_port == 0 || !_enable_send) {
657 // cerr << "Not delivering MMC " << _mmc->port() << " - " << session_send_mmc << endl;
661 MIDI::byte buffer[32];
662 MIDI::byte* b = c.fill_buffer (this, buffer);
664 if (_output_port->midimsg (buffer, b - buffer, when)) {
665 error << "MMC: cannot send command" << endmsg;
670 MachineControl::spp_start ()
672 SPPStart (); /* EMIT SIGNAL */
676 MachineControl::spp_continue ()
678 SPPContinue (); /* EMIT SIGNAL */
682 MachineControl::spp_stop ()
684 SPPStop (); /* EMIT SIGNAL */
687 MachineControlCommand::MachineControlCommand (MachineControl::Command c)
693 MachineControlCommand::MachineControlCommand (Timecode::Time t)
694 : _command (MachineControl::cmdLocate)
701 MachineControlCommand::fill_buffer (MachineControl* mmc, MIDI::byte* b) const
703 *b++ = 0xf0; // SysEx
704 *b++ = 0x7f; // Real-time SysEx ID for MMC
705 *b++ = mmc->send_device_id();
706 *b++ = 0x6; // MMC command
710 if (_command == MachineControl::cmdLocate) {
711 *b++ = 0x6; // byte count
712 *b++ = 0x1; // "TARGET" subcommand
713 *b++ = _time.hours % 24;
714 *b++ = _time.minutes;
715 *b++ = _time.seconds;
717 *b++ = _time.subframes;