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 "pbd/error.h"
26 #include "midi++/mmc.h"
27 #include "midi++/port.h"
28 #include "midi++/parser.h"
29 #include "midi++/manager.h"
35 static std::map
<int,string
> mmc_cmd_map
;
36 static void build_mmc_cmd_map ()
38 pair
<int,string
> newpair
;
41 newpair
.second
= "Stop";
42 mmc_cmd_map
.insert (newpair
);
45 newpair
.second
= "Play";
46 mmc_cmd_map
.insert (newpair
);
49 newpair
.second
= "DeferredPlay";
50 mmc_cmd_map
.insert (newpair
);
53 newpair
.second
= "FastForward";
54 mmc_cmd_map
.insert (newpair
);
57 newpair
.second
= "Rewind";
58 mmc_cmd_map
.insert (newpair
);
61 newpair
.second
= "RecordStrobe";
62 mmc_cmd_map
.insert (newpair
);
65 newpair
.second
= "RecordExit";
66 mmc_cmd_map
.insert (newpair
);
69 newpair
.second
= "RecordPause";
70 mmc_cmd_map
.insert (newpair
);
73 newpair
.second
= "Pause";
74 mmc_cmd_map
.insert (newpair
);
77 newpair
.second
= "Eject";
78 mmc_cmd_map
.insert (newpair
);
81 newpair
.second
= "Chase";
82 mmc_cmd_map
.insert (newpair
);
85 newpair
.second
= "CommandErrorReset";
86 mmc_cmd_map
.insert (newpair
);
89 newpair
.second
= "MmcReset";
90 mmc_cmd_map
.insert (newpair
);
93 newpair
.second
= "Illegal Mackie Jog Start";
94 mmc_cmd_map
.insert (newpair
);
97 newpair
.second
= "Illegal Mackie Jog Stop";
98 mmc_cmd_map
.insert (newpair
);
100 newpair
.first
= 0x40;
101 newpair
.second
= "Write";
102 mmc_cmd_map
.insert (newpair
);
104 newpair
.first
= 0x41;
105 newpair
.second
= "MaskedWrite";
106 mmc_cmd_map
.insert (newpair
);
108 newpair
.first
= 0x42;
109 newpair
.second
= "Read";
110 mmc_cmd_map
.insert (newpair
);
112 newpair
.first
= 0x43;
113 newpair
.second
= "Update";
114 mmc_cmd_map
.insert (newpair
);
116 newpair
.first
= 0x44;
117 newpair
.second
= "Locate";
118 mmc_cmd_map
.insert (newpair
);
120 newpair
.first
= 0x45;
121 newpair
.second
= "VariablePlay";
122 mmc_cmd_map
.insert (newpair
);
124 newpair
.first
= 0x46;
125 newpair
.second
= "Search";
126 mmc_cmd_map
.insert (newpair
);
128 newpair
.first
= 0x47;
129 newpair
.second
= "Shuttle";
130 mmc_cmd_map
.insert (newpair
);
132 newpair
.first
= 0x48;
133 newpair
.second
= "Step";
134 mmc_cmd_map
.insert (newpair
);
136 newpair
.first
= 0x49;
137 newpair
.second
= "AssignSystemMaster";
138 mmc_cmd_map
.insert (newpair
);
140 newpair
.first
= 0x4A;
141 newpair
.second
= "GeneratorCommand";
142 mmc_cmd_map
.insert (newpair
);
144 newpair
.first
= 0x4B;
145 newpair
.second
= "MtcCommand";
146 mmc_cmd_map
.insert (newpair
);
148 newpair
.first
= 0x4C;
149 newpair
.second
= "Move";
150 mmc_cmd_map
.insert (newpair
);
152 newpair
.first
= 0x4D;
153 newpair
.second
= "Add";
154 mmc_cmd_map
.insert (newpair
);
156 newpair
.first
= 0x4E;
157 newpair
.second
= "Subtract";
158 mmc_cmd_map
.insert (newpair
);
160 newpair
.first
= 0x4F;
161 newpair
.second
= "DropFrameAdjust";
162 mmc_cmd_map
.insert (newpair
);
164 newpair
.first
= 0x50;
165 newpair
.second
= "Procedure";
166 mmc_cmd_map
.insert (newpair
);
168 newpair
.first
= 0x51;
169 newpair
.second
= "Event";
170 mmc_cmd_map
.insert (newpair
);
172 newpair
.first
= 0x52;
173 newpair
.second
= "Group";
174 mmc_cmd_map
.insert (newpair
);
176 newpair
.first
= 0x53;
177 newpair
.second
= "CommandSegment";
178 mmc_cmd_map
.insert (newpair
);
180 newpair
.first
= 0x54;
181 newpair
.second
= "DeferredVariablePlay";
182 mmc_cmd_map
.insert (newpair
);
184 newpair
.first
= 0x55;
185 newpair
.second
= "RecordStrobeVariable";
186 mmc_cmd_map
.insert (newpair
);
188 newpair
.first
= 0x7C;
189 newpair
.second
= "Wait";
190 mmc_cmd_map
.insert (newpair
);
192 newpair
.first
= 0x7F;
193 newpair
.second
= "Resume";
194 mmc_cmd_map
.insert (newpair
);
198 MachineControl::MachineControl (Manager
* m
, jack_client_t
* jack
)
200 build_mmc_cmd_map ();
202 _receive_device_id
= 0x7f;
203 _send_device_id
= 0x7f;
205 _input_port
= m
->add_port (new Port ("MMC in", Port::IsInput
, jack
));
206 _output_port
= m
->add_port (new Port ("MMC out", Port::IsOutput
, jack
));
208 _input_port
->parser()->mmc
.connect_same_thread (port_connections
, boost::bind (&MachineControl::process_mmc_message
, this, _1
, _2
, _3
));
209 _input_port
->parser()->start
.connect_same_thread (port_connections
, boost::bind (&MachineControl::spp_start
, this, _1
, _2
));
210 _input_port
->parser()->contineu
.connect_same_thread (port_connections
, boost::bind (&MachineControl::spp_continue
, this, _1
, _2
));
211 _input_port
->parser()->stop
.connect_same_thread (port_connections
, boost::bind (&MachineControl::spp_stop
, this, _1
, _2
));
215 MachineControl::set_receive_device_id (byte id
)
217 _receive_device_id
= id
& 0x7f;
221 MachineControl::set_send_device_id (byte id
)
223 _send_device_id
= id
& 0x7f;
227 MachineControl::is_mmc (byte
*sysex_buf
, size_t len
)
229 if (len
< 4 || len
> 48) {
233 if (sysex_buf
[1] != 0x7f) {
237 if (sysex_buf
[3] != 0x6 && /* MMC Command */
238 sysex_buf
[3] != 0x7) { /* MMC Response */
246 MachineControl::process_mmc_message (Parser
&, byte
*msg
, size_t len
)
252 /* Reject if its not for us. 0x7f is the "all-call" device ID */
254 /* msg[0] = 0x7f (MMC sysex ID(
256 msg[2] = 0x6 (MMC command) or 0x7 (MMC response)
257 msg[3] = MMC command code
258 msg[4] = (typically) byte count for following part of command
262 cerr
<< "*** me = " << (int) _receive_device_id
<< " MMC message: len = " << len
<< "\n\t";
263 for (size_t i
= 0; i
< len
; i
++) {
264 cerr
<< hex
<< (int) msg
[i
] << dec
<< ' ';
269 if (msg
[1] != 0x7f && msg
[1] != _receive_device_id
) {
280 /* this works for all non-single-byte "counted"
281 commands. we set it to 1 for the exceptions.
284 std::map
<int,string
>::iterator x
= mmc_cmd_map
.find ((int)mmc_msg
[0]);
285 string cmdname
= "unknown";
287 if (x
!= mmc_cmd_map
.end()) {
288 cmdname
= (*x
).second
;
292 cerr
<< "+++ MMC type "
296 << " \"" << cmdname
<< "\" "
303 /* SINGLE-BYTE, UNCOUNTED COMMANDS */
315 case cmdDeferredPlay
:
316 DeferredPlay (*this);
330 case cmdRecordStrobe
:
331 RecordStrobe (*this);
360 case cmdCommandErrorReset
:
361 CommandErrorReset (*this);
370 case cmdIllegalMackieJogStart
:
375 case cmdIllegalMackieJogStop
:
380 /* END OF SINGLE-BYTE, UNCOUNTED COMMANDS */
383 do_masked_write (mmc_msg
, len
);
387 do_locate (mmc_msg
, len
);
391 do_shuttle (mmc_msg
, len
);
395 do_step (mmc_msg
, len
);
401 case cmdVariablePlay
:
403 case cmdAssignSystemMaster
:
404 case cmdGeneratorCommand
:
409 case cmdDropFrameAdjust
:
413 case cmdCommandSegment
:
414 case cmdDeferredVariablePlay
:
415 case cmdRecordStrobeVariable
:
418 error
<< "MIDI::MachineControl: unimplemented MMC command "
419 << hex
<< (int) *mmc_msg
<< dec
425 error
<< "MIDI::MachineControl: unknown MMC command "
426 << hex
<< (int) *mmc_msg
<< dec
432 /* increase skiplen to cover the command byte and
433 count byte (if it existed).
437 skiplen
= mmc_msg
[1] + 2;
442 if (len
<= skiplen
) {
449 } while (len
> 1); /* skip terminating EOX byte */
453 MachineControl::do_masked_write (byte
*msg
, size_t len
)
455 /* return the number of bytes "consumed" */
457 int retval
= msg
[1] + 2; /* bytes following + 2 */
460 case 0x4f: /* Track Record Ready Status */
461 write_track_status (&msg
[3], len
- 3, msg
[2]);
464 case 0x62: /* track mute */
465 write_track_status (&msg
[3], len
- 3, msg
[2]);
469 warning
<< "MIDI::MachineControl: masked write to "
470 << hex
<< (int) msg
[2] << dec
471 << " not implemented"
479 MachineControl::write_track_status (byte
*msg
, size_t /*len*/, byte reg
)
484 /* Bits 0-4 of the first byte are for special tracks:
492 the format of the message (its an MMC Masked Write) is:
495 <count> byte count of following data
496 <name> byte value of the field being written
497 <byte #> byte number of target byte in the
498 bitmap being written to
499 <mask> ones in the mask indicate which bits will be changed
500 <data> new data for the byte being written
502 by the time this code is executing, msg[0] is the
503 byte number of the target byte. if its zero, we
504 are writing to a special byte in the standard
505 track bitmap, in which the first 5 bits are
506 special. hence the bits for tracks 1 + 2 are bits
507 5 and 6 of the first byte of the track
510 change track 1: msg[0] = 0; << first byte of track bitmap
511 msg[1] = 0100000; << binary: bit 5 set
513 change track 2: msg[0] = 0; << first byte of track bitmap
514 msg[1] = 1000000; << binary: bit 6 set
516 change track 3: msg[0] = 1; << second byte of track bitmap
517 msg[1] = 0000001; << binary: bit 0 set
519 the (msg[0] * 8) - 6 computation is an attempt to
520 extract the value of the first track: ie. the one
521 that would be indicated by bit 0 being set.
523 so, if msg[0] = 0, msg[1] = 0100000 (binary),
524 what happens is that base_track = -5, but by the
525 time we check the correct bit, n = 5, and so the
526 computed track for the status change is 0 (first
529 if msg[0] = 1, then the base track for any change is 2 (the third track), and so on.
532 /* XXX check needed to make sure we don't go outside the
533 supported number of tracks.
539 base_track
= (msg
[0] * 8) - 6;
542 for (n
= 0; n
< 7; n
++) {
543 if (msg
[1] & (1<<n
)) {
545 /* Only touch tracks that have the "mask"
549 bool val
= (msg
[2] & (1<<n
));
553 trackRecordStatus
[base_track
+n
] = val
;
554 TrackRecordStatusChange (*this, base_track
+n
, val
);
558 trackMute
[base_track
+n
] = val
;
559 TrackMuteChange (*this, base_track
+n
, val
);
568 MachineControl::do_locate (byte
*msg
, size_t /*msglen*/)
571 warning
<< "MIDI::MMC: locate [I/F] command not supported"
576 /* regular "target" locate command */
578 Locate (*this, &msg
[3]);
583 MachineControl::do_step (byte
*msg
, size_t /*msglen*/)
585 int steps
= msg
[2] & 0x3f;
596 MachineControl::do_shuttle (byte
*msg
, size_t /*msglen*/)
613 left_shift
= (sh
& 0x38);
615 integral
= ((sh
& 0x7) << left_shift
) | (sm
>> (7 - left_shift
));
616 fractional
= ((sm
<< left_shift
) << 7) | sl
;
618 shuttle_speed
= integral
+
619 ((float)fractional
/ (1 << (14 - left_shift
)));
621 Shuttle (*this, shuttle_speed
, forward
);
627 MachineControl::enable_send (bool yn
)
632 /** Send a MMC command to a the MMC port.
636 MachineControl::send (MachineControlCommand
const & c
)
638 if (_output_port
== 0 || !_enable_send
) {
639 // cerr << "Not delivering MMC " << _mmc->port() << " - " << session_send_mmc << endl;
643 MIDI::byte buffer
[32];
644 MIDI::byte
* b
= c
.fill_buffer (this, buffer
);
646 if (_output_port
->midimsg (buffer
, b
- buffer
, 0)) {
647 error
<< "MMC: cannot send command" << endmsg
;
652 MachineControl::spp_start (Parser
& parser
, framecnt_t timestamp
)
654 SPPStart (parser
, timestamp
); /* EMIT SIGNAL */
658 MachineControl::spp_continue (Parser
& parser
, framecnt_t timestamp
)
660 SPPContinue (parser
, timestamp
); /* EMIT SIGNAL */
664 MachineControl::spp_stop (Parser
& parser
, framecnt_t timestamp
)
666 SPPStop (parser
, timestamp
); /* EMIT SIGNAL */
669 MachineControlCommand::MachineControlCommand (MachineControl::Command c
)
675 MachineControlCommand::MachineControlCommand (Timecode::Time t
)
676 : _command (MachineControl::cmdLocate
)
683 MachineControlCommand::fill_buffer (MachineControl
* mmc
, MIDI::byte
* b
) const
685 *b
++ = 0xf0; // SysEx
686 *b
++ = 0x7f; // Real-time SysEx ID for MMC
687 *b
++ = mmc
->send_device_id();
688 *b
++ = 0x6; // MMC command
692 if (_command
== MachineControl::cmdLocate
) {
693 *b
++ = 0x6; // byte count
694 *b
++ = 0x1; // "TARGET" subcommand
696 *b
++ = _time
.minutes
;
697 *b
++ = _time
.seconds
;
699 *b
++ = _time
.subframes
;