Remove erroneous assert which I added earlier.
[ardour2.git] / libs / midi++2 / mmc.cc
blob292b6cc1b4ff105242eb02f54ca0a86b4d4bb1b4
1 /*
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.
18 $Id$
21 #include <fcntl.h>
22 #include <map>
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"
31 using namespace std;
32 using namespace MIDI;
33 using namespace PBD;
35 static std::map<int,string> mmc_cmd_map;
36 static void build_mmc_cmd_map ()
38 pair<int,string> newpair;
40 newpair.first = 0x1;
41 newpair.second = "Stop";
42 mmc_cmd_map.insert (newpair);
44 newpair.first = 0x2;
45 newpair.second = "Play";
46 mmc_cmd_map.insert (newpair);
48 newpair.first = 0x3;
49 newpair.second = "DeferredPlay";
50 mmc_cmd_map.insert (newpair);
52 newpair.first = 0x4;
53 newpair.second = "FastForward";
54 mmc_cmd_map.insert (newpair);
56 newpair.first = 0x5;
57 newpair.second = "Rewind";
58 mmc_cmd_map.insert (newpair);
60 newpair.first = 0x6;
61 newpair.second = "RecordStrobe";
62 mmc_cmd_map.insert (newpair);
64 newpair.first = 0x7;
65 newpair.second = "RecordExit";
66 mmc_cmd_map.insert (newpair);
68 newpair.first = 0x8;
69 newpair.second = "RecordPause";
70 mmc_cmd_map.insert (newpair);
72 newpair.first = 0x9;
73 newpair.second = "Pause";
74 mmc_cmd_map.insert (newpair);
76 newpair.first = 0xA;
77 newpair.second = "Eject";
78 mmc_cmd_map.insert (newpair);
80 newpair.first = 0xB;
81 newpair.second = "Chase";
82 mmc_cmd_map.insert (newpair);
84 newpair.first = 0xC;
85 newpair.second = "CommandErrorReset";
86 mmc_cmd_map.insert (newpair);
88 newpair.first = 0xD;
89 newpair.second = "MmcReset";
90 mmc_cmd_map.insert (newpair);
92 newpair.first = 0x20;
93 newpair.second = "Illegal Mackie Jog Start";
94 mmc_cmd_map.insert (newpair);
96 newpair.first = 0x21;
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));
214 void
215 MachineControl::set_receive_device_id (byte id)
217 _receive_device_id = id & 0x7f;
220 void
221 MachineControl::set_send_device_id (byte id)
223 _send_device_id = id & 0x7f;
226 bool
227 MachineControl::is_mmc (byte *sysex_buf, size_t len)
229 if (len < 4 || len > 48) {
230 return false;
233 if (sysex_buf[1] != 0x7f) {
234 return false;
237 if (sysex_buf[3] != 0x6 && /* MMC Command */
238 sysex_buf[3] != 0x7) { /* MMC Response */
239 return false;
242 return true;
245 void
246 MachineControl::process_mmc_message (Parser &, byte *msg, size_t len)
248 size_t skiplen;
249 byte *mmc_msg;
250 bool single_byte;
252 /* Reject if its not for us. 0x7f is the "all-call" device ID */
254 /* msg[0] = 0x7f (MMC sysex ID(
255 msg[1] = device 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
261 #if 0
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 << ' ';
266 cerr << endl;
267 #endif
269 if (msg[1] != 0x7f && msg[1] != _receive_device_id) {
270 return;
273 mmc_msg = &msg[3];
274 len -= 3;
276 do {
278 single_byte = false;
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;
291 #if 0
292 cerr << "+++ MMC type "
293 << hex
294 << ((int) *mmc_msg)
295 << dec
296 << " \"" << cmdname << "\" "
297 << " len = " << len
298 << endl;
299 #endif
301 switch (*mmc_msg) {
303 /* SINGLE-BYTE, UNCOUNTED COMMANDS */
305 case cmdStop:
306 Stop (*this);
307 single_byte = true;
308 break;
310 case cmdPlay:
311 Play (*this);
312 single_byte = true;
313 break;
315 case cmdDeferredPlay:
316 DeferredPlay (*this);
317 single_byte = true;
318 break;
320 case cmdFastForward:
321 FastForward (*this);
322 single_byte = true;
323 break;
325 case cmdRewind:
326 Rewind (*this);
327 single_byte = true;
328 break;
330 case cmdRecordStrobe:
331 RecordStrobe (*this);
332 single_byte = true;
333 break;
335 case cmdRecordExit:
336 RecordExit (*this);
337 single_byte = true;
338 break;
340 case cmdRecordPause:
341 RecordPause (*this);
342 single_byte = true;
343 break;
345 case cmdPause:
346 Pause (*this);
347 single_byte = true;
348 break;
350 case cmdEject:
351 Eject (*this);
352 single_byte = true;
353 break;
355 case cmdChase:
356 Chase (*this);
357 single_byte = true;
358 break;
360 case cmdCommandErrorReset:
361 CommandErrorReset (*this);
362 single_byte = true;
363 break;
365 case cmdMmcReset:
366 MmcReset (*this);
367 single_byte = true;
368 break;
370 case cmdIllegalMackieJogStart:
371 JogStart (*this);
372 single_byte = true;
373 break;
375 case cmdIllegalMackieJogStop:
376 JogStop (*this);
377 single_byte = true;
378 break;
380 /* END OF SINGLE-BYTE, UNCOUNTED COMMANDS */
382 case cmdMaskedWrite:
383 do_masked_write (mmc_msg, len);
384 break;
386 case cmdLocate:
387 do_locate (mmc_msg, len);
388 break;
390 case cmdShuttle:
391 do_shuttle (mmc_msg, len);
392 break;
394 case cmdStep:
395 do_step (mmc_msg, len);
396 break;
398 case cmdWrite:
399 case cmdRead:
400 case cmdUpdate:
401 case cmdVariablePlay:
402 case cmdSearch:
403 case cmdAssignSystemMaster:
404 case cmdGeneratorCommand:
405 case cmdMtcCommand:
406 case cmdMove:
407 case cmdAdd:
408 case cmdSubtract:
409 case cmdDropFrameAdjust:
410 case cmdProcedure:
411 case cmdEvent:
412 case cmdGroup:
413 case cmdCommandSegment:
414 case cmdDeferredVariablePlay:
415 case cmdRecordStrobeVariable:
416 case cmdWait:
417 case cmdResume:
418 error << "MIDI::MachineControl: unimplemented MMC command "
419 << hex << (int) *mmc_msg << dec
420 << endmsg;
422 break;
424 default:
425 error << "MIDI::MachineControl: unknown MMC command "
426 << hex << (int) *mmc_msg << dec
427 << endmsg;
429 break;
432 /* increase skiplen to cover the command byte and
433 count byte (if it existed).
436 if (!single_byte) {
437 skiplen = mmc_msg[1] + 2;
438 } else {
439 skiplen = 1;
442 if (len <= skiplen) {
443 break;
446 mmc_msg += skiplen;
447 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 */
459 switch (msg[2]) {
460 case 0x4f: /* Track Record Ready Status */
461 write_track_status (&msg[3], len - 3, msg[2]);
462 break;
464 case 0x62: /* track mute */
465 write_track_status (&msg[3], len - 3, msg[2]);
466 break;
468 default:
469 warning << "MIDI::MachineControl: masked write to "
470 << hex << (int) msg[2] << dec
471 << " not implemented"
472 << endmsg;
475 return retval;
478 void
479 MachineControl::write_track_status (byte *msg, size_t /*len*/, byte reg)
481 size_t n;
482 ssize_t base_track;
484 /* Bits 0-4 of the first byte are for special tracks:
486 bit 0: video
487 bit 1: reserved
488 bit 2: time code
489 bit 3: aux track a
490 bit 4: aux track b
492 the format of the message (its an MMC Masked Write) is:
494 0x41 Command Code
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
508 bitmap. so:
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
527 track).
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.
536 if (msg[0] == 0) {
537 base_track = -5;
538 } else {
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"
546 bit set.
549 bool val = (msg[2] & (1<<n));
551 switch (reg) {
552 case 0x4f:
553 trackRecordStatus[base_track+n] = val;
554 TrackRecordStatusChange (*this, base_track+n, val);
555 break;
557 case 0x62:
558 trackMute[base_track+n] = val;
559 TrackMuteChange (*this, base_track+n, val);
560 break;
568 MachineControl::do_locate (byte *msg, size_t /*msglen*/)
570 if (msg[2] == 0) {
571 warning << "MIDI::MMC: locate [I/F] command not supported"
572 << endmsg;
573 return 0;
576 /* regular "target" locate command */
578 Locate (*this, &msg[3]);
579 return 0;
583 MachineControl::do_step (byte *msg, size_t /*msglen*/)
585 int steps = msg[2] & 0x3f;
587 if (msg[2] & 0x40) {
588 steps = -steps;
591 Step (*this, steps);
592 return 0;
596 MachineControl::do_shuttle (byte *msg, size_t /*msglen*/)
598 size_t forward;
599 byte sh = msg[2];
600 byte sm = msg[3];
601 byte sl = msg[4];
602 size_t left_shift;
603 size_t integral;
604 size_t fractional;
605 float shuttle_speed;
607 if (sh & (1<<6)) {
608 forward = false;
609 } else {
610 forward = true;
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);
623 return 0;
626 void
627 MachineControl::enable_send (bool yn)
629 _enable_send = yn;
632 /** Send a MMC command to a the MMC port.
633 * @param c command.
635 void
636 MachineControl::send (MachineControlCommand const & c)
638 if (_output_port == 0 || !_enable_send) {
639 // cerr << "Not delivering MMC " << _mmc->port() << " - " << session_send_mmc << endl;
640 return;
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;
651 void
652 MachineControl::spp_start (Parser& parser, framecnt_t timestamp)
654 SPPStart (parser, timestamp); /* EMIT SIGNAL */
657 void
658 MachineControl::spp_continue (Parser& parser, framecnt_t timestamp)
660 SPPContinue (parser, timestamp); /* EMIT SIGNAL */
663 void
664 MachineControl::spp_stop (Parser& parser, framecnt_t timestamp)
666 SPPStop (parser, timestamp); /* EMIT SIGNAL */
669 MachineControlCommand::MachineControlCommand (MachineControl::Command c)
670 : _command (c)
675 MachineControlCommand::MachineControlCommand (Timecode::Time t)
676 : _command (MachineControl::cmdLocate)
677 , _time (t)
682 MIDI::byte *
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
690 *b++ = _command;
692 if (_command == MachineControl::cmdLocate) {
693 *b++ = 0x6; // byte count
694 *b++ = 0x1; // "TARGET" subcommand
695 *b++ = _time.hours;
696 *b++ = _time.minutes;
697 *b++ = _time.seconds;
698 *b++ = _time.frames;
699 *b++ = _time.subframes;
702 *b++ = 0xf7;
704 return b;