merge with master, fixing conflicts in 3 wscript files
[ardour.git] / libs / midi++2 / mmc.cc
1 /*
2     Copyright (C) 2000 Paul Barton-Davis 
3
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.
8
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.
13
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.
17
18     $Id$
19 */
20
21 #include <fcntl.h>
22 #include <map>
23
24 #include "timecode/time.h"
25
26 #include "pbd/error.h"
27
28 #include "midi++/mmc.h"
29 #include "midi++/port.h"
30 #include "midi++/parser.h"
31
32 #ifndef __INT_MAX__   // 'ssize_t' won't be defined yet
33 typedef long ssize_t;
34 #endif
35
36 using namespace std;
37 using namespace MIDI;
38 using namespace PBD;
39
40 static std::map<int,string> mmc_cmd_map;
41 static void build_mmc_cmd_map ()
42 {
43         pair<int,string> newpair;
44
45         newpair.first = 0x1;
46         newpair.second = "Stop";
47         mmc_cmd_map.insert (newpair);
48
49         newpair.first = 0x2;
50         newpair.second = "Play";
51         mmc_cmd_map.insert (newpair);
52
53         newpair.first = 0x3;
54         newpair.second = "DeferredPlay";
55         mmc_cmd_map.insert (newpair);
56
57         newpair.first = 0x4;
58         newpair.second = "FastForward";
59         mmc_cmd_map.insert (newpair);
60
61         newpair.first = 0x5;
62         newpair.second = "Rewind";
63         mmc_cmd_map.insert (newpair);
64
65         newpair.first = 0x6;
66         newpair.second = "RecordStrobe";
67         mmc_cmd_map.insert (newpair);
68
69         newpair.first = 0x7;
70         newpair.second = "RecordExit";
71         mmc_cmd_map.insert (newpair);
72
73         newpair.first = 0x8;
74         newpair.second = "RecordPause";
75         mmc_cmd_map.insert (newpair);
76
77         newpair.first = 0x9;
78         newpair.second = "Pause";
79         mmc_cmd_map.insert (newpair);
80
81         newpair.first = 0xA;
82         newpair.second = "Eject";
83         mmc_cmd_map.insert (newpair);
84
85         newpair.first = 0xB;
86         newpair.second = "Chase";
87         mmc_cmd_map.insert (newpair);
88
89         newpair.first = 0xC;
90         newpair.second = "CommandErrorReset";
91         mmc_cmd_map.insert (newpair);
92
93         newpair.first = 0xD;
94         newpair.second = "MmcReset";
95         mmc_cmd_map.insert (newpair);
96
97         newpair.first = 0x20;
98         newpair.second = "Illegal Mackie Jog Start";
99         mmc_cmd_map.insert (newpair);
100
101         newpair.first = 0x21;
102         newpair.second = "Illegal Mackie Jog Stop";
103         mmc_cmd_map.insert (newpair);
104
105         newpair.first = 0x40;
106         newpair.second = "Write";
107         mmc_cmd_map.insert (newpair);
108
109         newpair.first = 0x41;
110         newpair.second = "MaskedWrite";
111         mmc_cmd_map.insert (newpair);
112
113         newpair.first = 0x42;
114         newpair.second = "Read";
115         mmc_cmd_map.insert (newpair);
116
117         newpair.first = 0x43;
118         newpair.second = "Update";
119         mmc_cmd_map.insert (newpair);
120
121         newpair.first = 0x44;
122         newpair.second = "Locate";
123         mmc_cmd_map.insert (newpair);
124
125         newpair.first = 0x45;
126         newpair.second = "VariablePlay";
127         mmc_cmd_map.insert (newpair);
128
129         newpair.first = 0x46;
130         newpair.second = "Search";
131         mmc_cmd_map.insert (newpair);
132
133         newpair.first = 0x47;
134         newpair.second = "Shuttle";
135         mmc_cmd_map.insert (newpair);
136
137         newpair.first = 0x48;
138         newpair.second = "Step";
139         mmc_cmd_map.insert (newpair);
140
141         newpair.first = 0x49;
142         newpair.second = "AssignSystemMaster";
143         mmc_cmd_map.insert (newpair);
144
145         newpair.first = 0x4A;
146         newpair.second = "GeneratorCommand";
147         mmc_cmd_map.insert (newpair);
148
149         newpair.first = 0x4B;
150         newpair.second = "MtcCommand";
151         mmc_cmd_map.insert (newpair);
152
153         newpair.first = 0x4C;
154         newpair.second = "Move";
155         mmc_cmd_map.insert (newpair);
156
157         newpair.first = 0x4D;
158         newpair.second = "Add";
159         mmc_cmd_map.insert (newpair);
160
161         newpair.first = 0x4E;
162         newpair.second = "Subtract";
163         mmc_cmd_map.insert (newpair);
164
165         newpair.first = 0x4F;
166         newpair.second = "DropFrameAdjust";
167         mmc_cmd_map.insert (newpair);
168
169         newpair.first = 0x50;
170         newpair.second = "Procedure";
171         mmc_cmd_map.insert (newpair);
172
173         newpair.first = 0x51;
174         newpair.second = "Event";
175         mmc_cmd_map.insert (newpair);
176
177         newpair.first = 0x52;
178         newpair.second = "Group";
179         mmc_cmd_map.insert (newpair);
180
181         newpair.first = 0x53;
182         newpair.second = "CommandSegment";
183         mmc_cmd_map.insert (newpair);
184
185         newpair.first = 0x54;
186         newpair.second = "DeferredVariablePlay";
187         mmc_cmd_map.insert (newpair);
188
189         newpair.first = 0x55;
190         newpair.second = "RecordStrobeVariable";
191         mmc_cmd_map.insert (newpair);
192
193         newpair.first = 0x7C;
194         newpair.second = "Wait";
195         mmc_cmd_map.insert (newpair);
196
197         newpair.first = 0x7F;
198         newpair.second = "Resume";
199         mmc_cmd_map.insert (newpair);
200 }
201
202 MachineControl::MachineControl ()
203 {
204         build_mmc_cmd_map ();
205
206         _receive_device_id = 0x7f;
207         _send_device_id = 0x7f;
208 }
209
210 void
211 MachineControl::set_ports (MIDI::Port* ip, MIDI::Port* op)
212 {
213         port_connections.drop_connections ();
214
215         _input_port = ip;
216         _output_port = op;
217
218         _input_port->parser()->mmc.connect_same_thread (port_connections, boost::bind (&MachineControl::process_mmc_message, this, _1, _2, _3));
219         _input_port->parser()->start.connect_same_thread (port_connections, boost::bind (&MachineControl::spp_start, this));
220         _input_port->parser()->contineu.connect_same_thread (port_connections, boost::bind (&MachineControl::spp_continue, this));
221         _input_port->parser()->stop.connect_same_thread (port_connections, boost::bind (&MachineControl::spp_stop, this));
222 }
223
224 void
225 MachineControl::set_receive_device_id (MIDI::byte id)
226 {
227         _receive_device_id = id & 0x7f;
228 }
229
230 void
231 MachineControl::set_send_device_id (MIDI::byte id)
232 {
233         _send_device_id = id & 0x7f;
234 }
235
236 bool
237 MachineControl::is_mmc (MIDI::byte *sysex_buf, size_t len)
238 {
239         if (len < 4 || len > 48) {
240                 return false;
241         }
242
243         if (sysex_buf[1] != 0x7f) {
244                 return false;
245         }
246
247         if (sysex_buf[3] != 0x6 && /* MMC Command */
248             sysex_buf[3] != 0x7) { /* MMC Response */
249                 return false;
250         }
251         
252         return true;
253 }
254
255 void
256 MachineControl::process_mmc_message (Parser &, MIDI::byte *msg, size_t len)
257 {
258         size_t skiplen;
259         byte *mmc_msg;
260         bool single_byte;
261
262         /* Reject if its not for us. 0x7f is the "all-call" device ID */
263
264         /* msg[0] = 0x7f (MMC sysex ID(
265            msg[1] = device ID
266            msg[2] = 0x6 (MMC command) or 0x7 (MMC response)
267            msg[3] = MMC command code
268            msg[4] = (typically) byte count for following part of command
269         */
270
271 #if 0
272         cerr << "*** me = " << (int) _receive_device_id << " MMC message: len = " << len << "\n\t";
273         for (size_t i = 0; i < len; i++) {
274                 cerr << hex << (int) msg[i] << dec << ' ';
275         }
276         cerr << endl;
277 #endif
278
279         if (msg[1] != 0x7f && msg[1] != _receive_device_id) {
280                 return;
281         }
282
283         mmc_msg = &msg[3];
284         len -= 3;
285
286         do {
287
288                 single_byte = false;
289
290                 /* this works for all non-single-byte "counted"
291                    commands. we set it to 1 for the exceptions.
292                 */
293
294                 std::map<int,string>::iterator x = mmc_cmd_map.find ((int)mmc_msg[0]);
295                 string cmdname = "unknown";
296
297                 if (x != mmc_cmd_map.end()) {
298                         cmdname = (*x).second;
299                 }
300
301 #if 0
302                 cerr << "+++ MMC type " 
303                      << hex
304                      << ((int) *mmc_msg)
305                      << dec
306                      << " \"" << cmdname << "\" "
307                      << " len = " << len
308                      << endl;
309 #endif
310
311                 switch (*mmc_msg) {
312
313                 /* SINGLE-BYTE, UNCOUNTED COMMANDS */
314
315                 case cmdStop:
316                         Stop (*this);
317                         single_byte = true;
318                         break;
319
320                 case cmdPlay:
321                         Play (*this);
322                         single_byte = true;
323                         break;
324
325                 case cmdDeferredPlay:
326                         DeferredPlay (*this);
327                         single_byte = true;
328                         break;
329
330                 case cmdFastForward:
331                         FastForward (*this);
332                         single_byte = true;
333                         break;
334
335                 case cmdRewind:
336                         Rewind (*this);
337                         single_byte = true;
338                         break;
339
340                 case cmdRecordStrobe:
341                         RecordStrobe (*this);
342                         single_byte = true;
343                         break;
344
345                 case cmdRecordExit:
346                         RecordExit (*this);
347                         single_byte = true;
348                         break;
349
350                 case cmdRecordPause:
351                         RecordPause (*this);
352                         single_byte = true;
353                         break;
354
355                 case cmdPause:
356                         Pause (*this);
357                         single_byte = true;
358                         break;
359
360                 case cmdEject:
361                         Eject (*this);
362                         single_byte = true;
363                         break;
364
365                 case cmdChase:
366                         Chase (*this);
367                         single_byte = true;
368                         break;
369
370                 case cmdCommandErrorReset:
371                         CommandErrorReset (*this);
372                         single_byte = true;
373                         break;
374
375                 case cmdMmcReset:
376                         MmcReset (*this);
377                         single_byte = true;
378                         break;
379
380                 case cmdIllegalMackieJogStart:
381                         JogStart (*this);
382                         single_byte = true;
383                         break;
384
385                 case cmdIllegalMackieJogStop:
386                         JogStop (*this);
387                         single_byte = true;
388                         break;
389
390                 /* END OF SINGLE-BYTE, UNCOUNTED COMMANDS */
391
392                 case cmdMaskedWrite:
393                         do_masked_write (mmc_msg, len);
394                         break;
395
396                 case cmdLocate:
397                         do_locate (mmc_msg, len);
398                         break;
399
400                 case cmdShuttle:
401                         do_shuttle (mmc_msg, len);
402                         break;
403
404                 case cmdStep:
405                         do_step (mmc_msg, len);
406                         break;
407
408                 case cmdWrite:
409                 case cmdRead:
410                 case cmdUpdate:
411                 case cmdVariablePlay:
412                 case cmdSearch:
413                 case cmdAssignSystemMaster:
414                 case cmdGeneratorCommand:
415                 case cmdMtcCommand:
416                 case cmdMove:
417                 case cmdAdd:
418                 case cmdSubtract:
419                 case cmdDropFrameAdjust:
420                 case cmdProcedure:
421                 case cmdEvent:
422                 case cmdGroup:
423                 case cmdCommandSegment:
424                 case cmdDeferredVariablePlay:
425                 case cmdRecordStrobeVariable:
426                 case cmdWait:
427                 case cmdResume:
428                         error << "MIDI::MachineControl: unimplemented MMC command "
429                               << hex << (int) *mmc_msg << dec
430                               << endmsg;
431
432                         break;
433
434                 default:
435                         error << "MIDI::MachineControl: unknown MMC command "
436                               << hex << (int) *mmc_msg << dec
437                               << endmsg;
438
439                         break;
440                 }
441
442                 /* increase skiplen to cover the command byte and 
443                    count byte (if it existed).
444                 */
445
446                 if (!single_byte) {
447                         skiplen = mmc_msg[1] + 2;
448                 } else {
449                         skiplen = 1;
450                 }
451
452                 if (len <= skiplen) {
453                         break;
454                 }
455
456                 mmc_msg += skiplen;
457                 len -= skiplen;
458
459         } while (len > 1); /* skip terminating EOX byte */
460 }               
461
462 int
463 MachineControl::do_masked_write (MIDI::byte *msg, size_t len)
464 {
465         /* return the number of bytes "consumed" */
466
467         int retval = msg[1] + 2; /* bytes following + 2 */
468         
469         switch (msg[2]) {
470         case 0x4f:  /* Track Record Ready Status */
471                 write_track_status (&msg[3], len - 3, msg[2]);
472                 break;
473
474         case 0x62: /* track mute */
475                 write_track_status (&msg[3], len - 3, msg[2]);
476                 break;
477
478         default:
479                 warning << "MIDI::MachineControl: masked write to "
480                         << hex << (int) msg[2] << dec
481                         << " not implemented"
482                         << endmsg;
483         }
484
485         return retval;
486 }
487
488 void
489 MachineControl::write_track_status (MIDI::byte *msg, size_t /*len*/, MIDI::byte reg)
490 {
491         size_t n;
492         ssize_t base_track;
493
494         /* Bits 0-4 of the first byte are for special tracks:
495
496            bit 0: video
497            bit 1: reserved
498            bit 2: time code
499            bit 3: aux track a
500            bit 4: aux track b
501
502            the format of the message (its an MMC Masked Write) is:
503            
504            0x41      Command Code
505            <count>   byte count of following data
506            <name>    byte value of the field being written
507            <byte #>  byte number of target byte in the 
508            bitmap being written to
509            <mask>    ones in the mask indicate which bits will be changed
510            <data>    new data for the byte being written
511            
512            by the time this code is executing, msg[0] is the
513            byte number of the target byte. if its zero, we
514            are writing to a special byte in the standard
515            track bitmap, in which the first 5 bits are
516            special. hence the bits for tracks 1 + 2 are bits
517            5 and 6 of the first byte of the track
518            bitmap. so:
519            
520            change track 1:  msg[0] = 0;       << first byte of track bitmap 
521                             msg[1] = 0100000; << binary: bit 5 set
522         
523            change track 2:  msg[0] = 0;       << first byte of track bitmap
524                             msg[1] = 1000000; << binary: bit 6 set
525         
526            change track 3:  msg[0] = 1;       << second byte of track bitmap
527                             msg[1] = 0000001; << binary: bit 0 set
528         
529            the (msg[0] * 8) - 6 computation is an attempt to
530            extract the value of the first track: ie. the one
531            that would be indicated by bit 0 being set.
532                 
533            so, if msg[0] = 0, msg[1] = 0100000 (binary),
534            what happens is that base_track = -5, but by the
535            time we check the correct bit, n = 5, and so the
536            computed track for the status change is 0 (first
537            track).
538
539            if msg[0] = 1, then the base track for any change is 2 (the third track), and so on.
540         */
541
542         /* XXX check needed to make sure we don't go outside the
543            supported number of tracks.
544         */
545
546         if (msg[0] == 0) {
547                 base_track = -5;
548         } else {
549                 base_track = (msg[0] * 8) - 6;
550         }
551
552         for (n = 0; n < 7; n++) {
553                 if (msg[1] & (1<<n)) {
554
555                         /* Only touch tracks that have the "mask"
556                            bit set.
557                         */
558
559                         bool val = (msg[2] & (1<<n));
560                         
561                         switch (reg) {
562                         case 0x4f:
563                                 trackRecordStatus[base_track+n] = val;
564                                 TrackRecordStatusChange (*this, base_track+n, val);
565                                 break;
566                                 
567                         case 0x62:
568                                 trackMute[base_track+n] = val;
569                                 TrackMuteChange (*this, base_track+n, val);
570                                 break;
571                         }
572                 } 
573
574         }
575 }
576
577 int
578 MachineControl::do_locate (MIDI::byte *msg, size_t /*msglen*/)
579 {
580         if (msg[2] == 0) {
581                 warning << "MIDI::MMC: locate [I/F] command not supported"
582                         << endmsg;
583                 return 0;
584         }
585
586         /* regular "target" locate command */
587
588         Locate (*this, &msg[3]);
589         return 0;
590 }
591
592 int
593 MachineControl::do_step (MIDI::byte *msg, size_t /*msglen*/)
594 {
595         int steps = msg[2] & 0x3f;
596
597         if (msg[2] & 0x40) {
598                 steps = -steps;
599         }
600
601         Step (*this, steps);
602         return 0;
603 }
604
605 int
606 MachineControl::do_shuttle (MIDI::byte *msg, size_t /*msglen*/)
607 {
608         size_t forward;
609         byte sh = msg[2];
610         byte sm = msg[3];
611         byte sl = msg[4];
612         size_t left_shift;
613         size_t integral;
614         size_t fractional;
615         float shuttle_speed;
616
617         if (sh & (1<<6)) {
618                 forward = false;
619         } else {
620                 forward = true;
621         }
622         
623         left_shift = (sh & 0x38);
624
625         integral = ((sh & 0x7) << left_shift) | (sm >> (7 - left_shift));
626         fractional = ((sm << left_shift) << 7) | sl;
627
628         shuttle_speed = integral + 
629                 ((float)fractional / (1 << (14 - left_shift)));
630
631         Shuttle (*this, shuttle_speed, forward);
632
633         return 0;
634 }
635
636 void
637 MachineControl::enable_send (bool yn)
638 {
639         _enable_send = yn;
640 }
641
642 /** Send a MMC command to a the MMC port.
643  *  @param c command.
644  */
645 void
646 MachineControl::send (MachineControlCommand const & c)
647 {
648         if (_output_port == 0 || !_enable_send) {
649                 // cerr << "Not delivering MMC " << _mmc->port() << " - " << session_send_mmc << endl;
650                 return;
651         }
652
653         MIDI::byte buffer[32];
654         MIDI::byte* b = c.fill_buffer (this, buffer);
655
656         if (_output_port->midimsg (buffer, b - buffer, 0)) {
657                 error << "MMC: cannot send command" << endmsg;
658         }
659 }
660
661 void
662 MachineControl::spp_start ()
663 {
664         SPPStart (); /* EMIT SIGNAL */
665 }
666
667 void
668 MachineControl::spp_continue ()
669 {
670         SPPContinue (); /* EMIT SIGNAL */
671 }
672
673 void
674 MachineControl::spp_stop ()
675 {
676         SPPStop (); /* EMIT SIGNAL */
677 }
678
679 MachineControlCommand::MachineControlCommand (MachineControl::Command c)
680         : _command (c)
681 {
682
683 }
684
685 MachineControlCommand::MachineControlCommand (Timecode::Time t)
686         : _command (MachineControl::cmdLocate)
687         , _time (t)
688 {
689
690 }
691
692 MIDI::byte * 
693 MachineControlCommand::fill_buffer (MachineControl* mmc, MIDI::byte* b) const
694 {
695         *b++ = 0xf0; // SysEx
696         *b++ = 0x7f; // Real-time SysEx ID for MMC
697         *b++ = mmc->send_device_id();
698         *b++ = 0x6; // MMC command
699
700         *b++ = _command;
701
702         if (_command == MachineControl::cmdLocate) {
703                 *b++ = 0x6; // byte count
704                 *b++ = 0x1; // "TARGET" subcommand
705                 *b++ = _time.hours;
706                 *b++ = _time.minutes;
707                 *b++ = _time.seconds;
708                 *b++ = _time.frames;
709                 *b++ = _time.subframes;
710         }
711
712         *b++ = 0xf7;
713
714         return b;
715 }
716