root/branches/libfreebob-2.0/src/motu/motu_avdevice.cpp

Revision 296, 25.3 kB (checked in by jwoithe, 18 years ago)

Code "ticks per frame" DLL inline to the MOTU receive stream processor for
efficiency. Fine-tune DLL integration coefficient to remove regular audio
glitches. Set teststreaming2.c to request realtime priority to facilitate
further testing. Cleanly deal with cycle wraparound in transmit stream
processor. Improve efficiency of 1 kHz tone generator in transmit stream
processor.

Line 
1 /* motu_avdevice.cpp
2  * Copyright (C) 2006 by Pieter Palmers
3  * Copyright (C) 2006 by Jonathan Woithe
4  *
5  * This file is part of FreeBob.
6  *
7  * FreeBob is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  * FreeBob is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with FreeBob; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
19  * MA 02111-1307 USA.
20  */
21
22 #include "motu/motu_avdevice.h"
23 #include "configrom.h"
24
25 #include "libfreebobavc/ieee1394service.h"
26 #include "libfreebobavc/avc_definitions.h"
27
28 #include "debugmodule/debugmodule.h"
29
30 #include "libstreaming/MotuStreamProcessor.h"
31 #include "libstreaming/MotuPort.h"
32
33 #include "libutil/DelayLockedLoop.h"
34
35 #include <string>
36 #include <stdint.h>
37 #include <assert.h>
38 #include <netinet/in.h>
39
40 #include <libraw1394/csr.h>
41
42 namespace Motu {
43
44 IMPL_DEBUG_MODULE( MotuDevice, MotuDevice, DEBUG_LEVEL_NORMAL );
45
46 char *motufw_modelname[] = {"[unknown]","828MkII", "Traveler"};
47
48 /* ======================================================================= */
49 /* Provide a mechanism for allocating iso channels and bandwidth to MOTU
50  * interfaces.
51  */
52
53 static signed int allocate_iso_channel(raw1394handle_t handle) {
54 /*
55  * Allocates an iso channel for use by the interface in a similar way to
56  * libiec61883.  Returns -1 on error (due to there being no free channels)
57  * or an allocated channel number.
58  * FIXME: As in libiec61883, channel 63 is not requested; this is either a
59  * bug or it's omitted since that's the channel preferred by video devices.
60  */
61         int c = -1;
62         for (c = 0; c < 63; c++)
63                 if (raw1394_channel_modify (handle, c, RAW1394_MODIFY_ALLOC) == 0)
64                         break;
65         if (c < 63)
66                 return c;
67         return -1;
68 }
69
70 static signed int free_iso_channel(raw1394handle_t handle, signed int channel) {
71 /*
72  * Deallocates an iso channel.  Returns -1 on error or 0 on success.  Silently
73  * ignores a request to deallocate a negative channel number.
74  */
75         if (channel < 0)
76                 return 0;
77         if (raw1394_channel_modify (handle, channel, RAW1394_MODIFY_FREE)!=0)
78                 return -1;
79         return 0;
80 }
81
82 static signed int get_iso_bandwidth_avail(raw1394handle_t handle) {
83 /*
84  * Returns the current value of the `bandwidth available' register on
85  * the IRM, or -1 on error.
86  */
87 quadlet_t buffer;
88 signed int result = raw1394_read (handle, raw1394_get_irm_id (handle),
89         CSR_REGISTER_BASE + CSR_BANDWIDTH_AVAILABLE,
90         sizeof (quadlet_t), &buffer);
91
92         if (result < 0)
93                 return -1;
94         return ntohl(buffer);
95 }
96 /* ======================================================================= */
97
98 MotuDevice::MotuDevice( Ieee1394Service& ieee1394service,
99                         int nodeId,
100                         int verboseLevel )
101     : m_1394Service( &ieee1394service )
102     , m_motu_model( MOTUFW_MODEL_NONE )
103     , m_nodeId( nodeId )
104     , m_verboseLevel( verboseLevel )
105     , m_id(0)
106     , m_iso_recv_channel ( -1 )
107     , m_iso_send_channel ( -1 )
108     , m_bandwidth ( -1 )
109     , m_receiveProcessor ( 0 )
110     , m_transmitProcessor ( 0 )
111    
112 {
113     if ( m_verboseLevel ) {
114         setDebugLevel( DEBUG_LEVEL_VERBOSE );
115     }
116     debugOutput( DEBUG_LEVEL_VERBOSE, "Created Motu::MotuDevice (NodeID %d)\n",
117                  nodeId );
118     m_configRom = new ConfigRom( m_1394Service, m_nodeId );
119     m_configRom->initialize();
120
121 }
122
123 MotuDevice::~MotuDevice()
124 {
125         // Free ieee1394 bus resources if they have been allocated
126         if (m_1394Service != NULL) {
127                 raw1394handle_t handle = m_1394Service->getHandle();
128                 if (m_bandwidth >= 0)
129                         if (raw1394_bandwidth_modify(handle, m_bandwidth, RAW1394_MODIFY_FREE) < 0)
130                                 debugOutput(DEBUG_LEVEL_VERBOSE, "Could not free bandwidth of %d\n", m_bandwidth);
131                 if (m_iso_recv_channel >= 0)
132                         if (raw1394_channel_modify(handle, m_iso_recv_channel, RAW1394_MODIFY_FREE) < 0)
133                                 debugOutput(DEBUG_LEVEL_VERBOSE, "Could not free recv iso channel %d\n", m_iso_recv_channel);
134                 if (m_iso_send_channel >= 0)
135                         if (raw1394_channel_modify(handle, m_iso_send_channel, RAW1394_MODIFY_FREE) < 0)
136                                 debugOutput(DEBUG_LEVEL_VERBOSE, "Could not free send iso channel %d\n", m_iso_send_channel);
137         }
138         delete m_configRom;
139 }
140
141 ConfigRom&
142 MotuDevice::getConfigRom() const
143 {
144     return *m_configRom;
145 }
146
147 bool
148 MotuDevice::discover()
149 {
150         // Find out if this device is one we know about
151         if (m_configRom->getUnitSpecifierId() == MOTUFW_VENDOR_MOTU) {
152                 switch (m_configRom->getUnitVersion()) {
153                     case MOTUFW_UNITVER_828mkII:
154                         m_motu_model = MOTUFW_MODEL_828mkII;
155                         break;
156                     case MOTUFW_UNITVER_TRAVELER:
157                         m_motu_model = MOTUFW_MODEL_TRAVELER;
158                         break;
159                 }
160         }
161         if (m_motu_model != MOTUFW_MODEL_NONE) {
162                 debugOutput( DEBUG_LEVEL_VERBOSE, "found MOTU %s\n",
163                         motufw_modelname[m_motu_model]);
164                 return true;
165         }
166
167         return false;
168 }
169
170 int
171 MotuDevice::getSamplingFrequency( ) {
172     /*
173      Implement the procedure to retrieve the samplerate here
174     */
175     quadlet_t q = ReadRegister(MOTUFW_REG_RATECTRL);
176     int rate = 0;
177
178     switch (q & MOTUFW_BASE_RATE_MASK) {
179         case MOTUFW_BASE_RATE_44100:
180             rate = 44100;
181             break;
182         case MOTUFW_BASE_RATE_48000:
183             rate = 48000;
184             break;
185     }
186     switch (q & MOTUFW_RATE_MULTIPLIER_MASK) {
187         case MOTUFW_RATE_MULTIPLIER_2X:
188             rate *= 2;
189             break;
190         case MOTUFW_RATE_MULTIPLIER_4X:
191             rate *= 4;
192             break;
193     }
194     return rate;
195 }
196
197 bool
198 MotuDevice::setSamplingFrequency( ESamplingFrequency samplingFrequency )
199 {
200     /*
201      Implement the procedure to set the samplerate here
202     */
203
204     quadlet_t new_rate=0;
205         int supported=true;
206
207     switch ( samplingFrequency ) {
208         case eSF_22050Hz:
209             supported=false;
210             break;
211         case eSF_24000Hz:
212             supported=false;
213             break;
214         case eSF_32000Hz:
215             supported=false;
216             break;
217         case eSF_44100Hz:
218             new_rate = MOTUFW_BASE_RATE_44100 | MOTUFW_RATE_MULTIPLIER_1X;
219             break;
220         case eSF_48000Hz:
221             new_rate = MOTUFW_BASE_RATE_48000 | MOTUFW_RATE_MULTIPLIER_1X;
222             break;
223         case eSF_88200Hz:
224             new_rate = MOTUFW_BASE_RATE_44100 | MOTUFW_RATE_MULTIPLIER_2X;
225             break;
226         case eSF_96000Hz:
227             new_rate = MOTUFW_BASE_RATE_48000 | MOTUFW_RATE_MULTIPLIER_2X;
228             break;
229         case eSF_176400Hz:
230             new_rate = MOTUFW_BASE_RATE_44100 | MOTUFW_RATE_MULTIPLIER_4X;
231             break;
232         case eSF_192000Hz:
233             new_rate = MOTUFW_BASE_RATE_48000 | MOTUFW_RATE_MULTIPLIER_4X;
234             break;
235         default:
236             supported=false;
237     }
238
239     // update the register.  FIXME: there's more to it than this
240     if (supported) {
241         quadlet_t value=ReadRegister(MOTUFW_REG_RATECTRL);
242         value &= ~(MOTUFW_BASE_RATE_MASK|MOTUFW_RATE_MULTIPLIER_MASK);
243         value |= new_rate;
244 //        value |= 0x04000000;
245         if (WriteRegister(MOTUFW_REG_RATECTRL, value) == 0) {
246             supported=true;
247         } else {
248             supported=false;
249         }
250     }
251     return supported;
252 }
253
254 bool MotuDevice::setId( unsigned int id) {
255     debugOutput( DEBUG_LEVEL_VERBOSE, "Set id to %d...\n", id);
256     m_id=id;
257     return true;
258 }
259
260 void
261 MotuDevice::showDevice() const
262 {
263     printf( "MOTU %s at node %d\n",
264         motufw_modelname[m_motu_model],
265         m_nodeId );
266 }
267
268 bool
269 MotuDevice::prepare() {
270
271         int samp_freq = getSamplingFrequency();
272         unsigned int optical_mode = getOpticalMode();
273         unsigned int event_size = getEventSize();
274
275         raw1394handle_t handle = m_1394Service->getHandle();
276
277         debugOutput(DEBUG_LEVEL_NORMAL, "Preparing MotuDevice...\n" );
278
279         // Assign iso channels if not already done
280         if (m_iso_recv_channel < 0)
281                 m_iso_recv_channel = allocate_iso_channel(handle);
282         if (m_iso_send_channel < 0)
283                 m_iso_send_channel = allocate_iso_channel(handle);
284
285         debugOutput(DEBUG_LEVEL_VERBOSE, "recv channel = %d, send channel = %d\n",
286                 m_iso_recv_channel, m_iso_send_channel);
287
288         if (m_iso_recv_channel<0 || m_iso_send_channel<0) {
289                 debugFatal("Could not allocate iso channels!\n");
290                 return false;
291         }
292
293         // Allocate bandwidth if not previously done.
294         // FIXME: The bandwidth allocation calculation can probably be
295         // refined somewhat since this is currently based on a rudimentary
296         // understanding of the iso protocol.
297         // Currently we assume the following.
298         //   * Ack/iso gap = 0.05 us
299         //   * DATA_PREFIX = 0.16 us
300         //   * DATA_END    = 0.26 us
301         // These numbers are the worst-case figures given in the ieee1394
302         // standard.  This gives approximately 0.5 us of overheads per
303         // packet - around 25 bandwidth allocation units (from the ieee1394
304         // standard 1 bandwidth allocation unit is 125/6144 us).  We further
305         // assume the MOTU is running at S400 (which it should be) so one
306         // allocation unit is equivalent to 1 transmitted byte; thus the
307         // bandwidth allocation required for the packets themselves is just
308         // the size of the packet.  We allocate based on the maximum packet
309         // size (1160 bytes at 192 kHz) so the sampling frequency can be
310         // changed dynamically if this ends up being useful in future.
311         m_bandwidth = 25 + 1160;
312         debugOutput(DEBUG_LEVEL_VERBOSE, "Available bandwidth: %d\n",
313                 get_iso_bandwidth_avail(handle));
314         if (raw1394_bandwidth_modify(handle, m_bandwidth, RAW1394_MODIFY_ALLOC) < 0) {
315                 debugFatal("Could not allocate bandwidth of %d\n", m_bandwidth);
316                 m_bandwidth = -1;
317                 return false;
318         }
319         debugOutput(DEBUG_LEVEL_VERBOSE,
320                 "allocated bandwidth of %d for MOTU device\n", m_bandwidth);
321         debugOutput(DEBUG_LEVEL_VERBOSE,
322                 "remaining bandwidth: %d\n", get_iso_bandwidth_avail(handle));
323
324         m_receiveProcessor=new FreebobStreaming::MotuReceiveStreamProcessor(
325                 m_1394Service->getPort(), samp_freq, event_size);
326                                  
327         // The first thing is to initialize the processor.  This creates the
328         // data structures.
329         if(!m_receiveProcessor->init()) {
330                 debugFatal("Could not initialize receive processor!\n");
331                 return false;
332         }
333         m_receiveProcessor->setVerboseLevel(getDebugLevel());
334
335         // Now we add ports to the processor
336         debugOutput(DEBUG_LEVEL_VERBOSE,"Adding ports to receive processor\n");
337        
338         char *buff;
339         unsigned int i;
340         FreebobStreaming::Port *p=NULL;
341
342         // Add audio capture ports
343         if (!addDirPorts(FreebobStreaming::Port::E_Capture, samp_freq, optical_mode)) {
344                 return false;
345         }
346
347         // example of adding an midi port:
348 //    asprintf(&buff,"dev%d_cap_%s",m_id,"myportnamehere");
349 //    p=new FreebobStreaming::MotuMidiPort(
350 //            buff,
351 //            FreebobStreaming::Port::E_Capture,
352 //            0 // you can add all other port specific stuff you
353 //              // need to pass by extending MotuXXXPort and MotuPortInfo
354 //    );
355 //    free(buff);
356 //
357 //    if (!p) {
358 //        debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n",buff);
359 //    } else {
360 //        if (!m_receiveProcessor->addPort(p)) {
361 //            debugWarning("Could not register port with stream processor\n");
362 //            return false;
363 //        } else {
364 //            debugOutput(DEBUG_LEVEL_VERBOSE, "Added port %s\n",buff);
365 //        }
366 //    }
367    
368         // example of adding an control port:
369 //    asprintf(&buff,"dev%d_cap_%s",m_id,"myportnamehere");
370 //    p=new FreebobStreaming::MotuControlPort(
371 //            buff,
372 //            FreebobStreaming::Port::E_Capture,
373 //            0 // you can add all other port specific stuff you
374 //              // need to pass by extending MotuXXXPort and MotuPortInfo
375 //    );
376 //    free(buff);
377 //
378 //    if (!p) {
379 //        debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n",buff);
380 //    } else {
381 //
382 //        if (!m_receiveProcessor->addPort(p)) {
383 //            debugWarning("Could not register port with stream processor\n");
384 //            return false;
385 //        } else {
386 //            debugOutput(DEBUG_LEVEL_VERBOSE, "Added port %s\n",buff);
387 //        }
388 //    }
389
390         // Do the same for the transmit processor
391         m_transmitProcessor=new FreebobStreaming::MotuTransmitStreamProcessor(
392                 m_1394Service->getPort(), getSamplingFrequency(), event_size);
393
394         m_transmitProcessor->setVerboseLevel(getDebugLevel());
395        
396         if(!m_transmitProcessor->init()) {
397                 debugFatal("Could not initialize transmit processor!\n");
398                 return false;
399         }
400
401         // Connect the transmit stream ticks-per-frame hook to the
402         // ticks-per-frame DLL integrator in the receive stream.
403         m_transmitProcessor->setTicksPerFrameDLL(m_receiveProcessor->getTicksPerFrameDLL());
404
405         // Now we add ports to the processor
406         debugOutput(DEBUG_LEVEL_VERBOSE,"Adding ports to transmit processor\n");
407
408         // Add audio playback ports
409         if (!addDirPorts(FreebobStreaming::Port::E_Playback, samp_freq, optical_mode)) {
410                 return false;
411         }
412
413 //      // example of adding an midi port:
414 //    asprintf(&buff,"dev%d_pbk_%s",m_id,"myportnamehere");
415 //   
416 //    p=new FreebobStreaming::MotuMidiPort(
417 //            buff,
418 //            FreebobStreaming::Port::E_Playback,
419 //            0 // you can add all other port specific stuff you
420 //              // need to pass by extending MotuXXXPort and MotuPortInfo
421 //    );
422 //    free(buff);
423 //
424 //    if (!p) {
425 //        debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n",buff);
426 //    } else {
427 //        if (!m_transmitProcessor->addPort(p)) {
428 //            debugWarning("Could not register port with stream processor\n");
429 //            return false;
430 //        } else {
431 //            debugOutput(DEBUG_LEVEL_VERBOSE, "Added port %s\n",buff);
432 //        }
433 //    }
434    
435         // example of adding an control port:
436 //    asprintf(&buff,"dev%d_pbk_%s",m_id,"myportnamehere");
437 //   
438 //    p=new FreebobStreaming::MotuControlPort(
439 //            buff,
440 //            FreebobStreaming::Port::E_Playback,
441 //            0 // you can add all other port specific stuff you
442 //              // need to pass by extending MotuXXXPort and MotuPortInfo
443 //    );
444 //    free(buff);
445 //
446 //    if (!p) {
447 //        debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n",buff);
448 //    } else {
449 //        if (!m_transmitProcessor->addPort(p)) {
450 //            debugWarning("Could not register port with stream processor\n");
451 //            return false;
452 //        } else {
453 //            debugOutput(DEBUG_LEVEL_VERBOSE, "Added port %s\n",buff);
454 //        }
455 //    }
456        
457         return true;
458 }
459
460 int
461 MotuDevice::getStreamCount() {
462         return 2; // one receive, one transmit
463 }
464
465 FreebobStreaming::StreamProcessor *
466 MotuDevice::getStreamProcessorByIndex(int i) {
467         switch (i) {
468         case 0:
469                 return m_receiveProcessor;
470         case 1:
471                 return m_transmitProcessor;
472         default:
473                 return NULL;
474         }
475         return 0;
476 }
477
478 int
479 MotuDevice::startStreamByIndex(int i) {
480
481 quadlet_t isoctrl = ReadRegister(MOTUFW_REG_ISOCTRL);
482
483         // NOTE: this assumes that you have two streams
484         switch (i) {
485         case 0:
486                 // TODO: do the stuff that is nescessary to make the device
487                 // transmit a stream
488
489                 // Set the streamprocessor channel to the one obtained by
490                 // the connection management
491                 m_receiveProcessor->setChannel(m_iso_recv_channel);
492
493                 // Mask out current transmit settings of the MOTU and replace
494                 // with new ones.  Turn bit 24 on to enable changes to the
495                 // MOTU's iso transmit settings when the iso control register
496                 // is written.  Bit 23 enables iso transmit from the MOTU.
497                 isoctrl &= 0xff00ffff;
498                 isoctrl |= (m_iso_recv_channel << 16);
499                 isoctrl |= 0x00c00000;
500                 WriteRegister(MOTUFW_REG_ISOCTRL, isoctrl);
501                 break;
502         case 1:
503                 // TODO: do the stuff that is nescessary to make the device
504                 // receive a stream
505
506                 // Set the streamprocessor channel to the one obtained by
507                 // the connection management
508                 m_transmitProcessor->setChannel(m_iso_send_channel);
509
510                 // Mask out current receive settings of the MOTU and replace
511                 // with new ones.  Turn bit 31 on to enable changes to the
512                 // MOTU's iso receive settings when the iso control register
513                 // is written.  Bit 30 enables iso receive by the MOTU.
514                 isoctrl &= 0x00ffffff;
515                 isoctrl |= (m_iso_send_channel << 24);
516                 isoctrl |= 0xc0000000;
517                 WriteRegister(MOTUFW_REG_ISOCTRL, isoctrl);
518                 break;
519                
520         default: // Invalid stream index
521                 return -1;
522         }
523
524         return 0;
525 }
526
527 int
528 MotuDevice::stopStreamByIndex(int i) {
529
530 quadlet_t isoctrl = ReadRegister(MOTUFW_REG_ISOCTRL);
531
532         // TODO: connection management: break connection
533         // cfr the start function
534
535         // NOTE: this assumes that you have two streams
536         switch (i) {
537         case 0:
538                 // Turn bit 22 off to disable iso send by the MOTU.  Turn
539                 // bit 23 on to enable changes to the MOTU's iso transmit
540                 // settings when the iso control register is written.
541                 isoctrl &= 0xffbfffff;
542                 isoctrl |= 0x00800000;
543                 WriteRegister(MOTUFW_REG_ISOCTRL, isoctrl);
544                 break;
545         case 1:
546                 // Turn bit 30 off to disable iso receive by the MOTU.  Turn
547                 // bit 31 on to enable changes to the MOTU's iso receive
548                 // settings when the iso control register is written.
549                 isoctrl &= 0xbfffffff;
550                 isoctrl |= 0x80000000;
551                 WriteRegister(MOTUFW_REG_ISOCTRL, isoctrl);
552                 break;
553                
554         default: // Invalid stream index
555                 return -1;
556         }
557
558         return 0;
559 }
560
561 signed int MotuDevice::getIsoRecvChannel(void) {
562         return m_iso_recv_channel;
563 }
564
565 signed int MotuDevice::getIsoSendChannel(void) {
566         return m_iso_send_channel;
567 }
568
569 unsigned int MotuDevice::getOpticalMode(void) {
570         unsigned int reg = ReadRegister(MOTUFW_REG_ROUTE_PORT_CONF);
571         return reg & MOTUFW_OPTICAL_MODE_MASK;
572 }
573
574 signed int MotuDevice::setOpticalMode(unsigned int mode) {
575         unsigned int reg = ReadRegister(MOTUFW_REG_ROUTE_PORT_CONF);
576
577         // FIXME: there seems to be more to it than this.
578         reg &= ~MOTUFW_OPTICAL_MODE_MASK;
579         reg |= mode & MOTUFW_OPTICAL_MODE_MASK;
580         return WriteRegister(MOTUFW_REG_ROUTE_PORT_CONF, reg);
581 }
582
583 signed int MotuDevice::getEventSize(void) {
584 //
585 // Return the size of a single event sent by the MOTU as part of an iso
586 // data packet in bytes.
587 //
588 // FIXME: for performance it may turn out best to calculate the event
589 // size in setOpticalMode and cache the result in a data field.  However,
590 // as it stands this will not adapt to dynamic changes in sample rate - we'd
591 // need a setFrameRate() for that.
592 //
593 // At the very least an event consists of the SPH (4 bytes), the control/MIDI
594 // bytes (6 bytes) and 8 analog audio channels (each 3 bytes long).  Note that
595 // all audio channels are sent using 3 bytes.
596 signed int sample_rate = getSamplingFrequency();
597 signed int optical_mode = getOpticalMode();
598 signed int size = 4+6+8*3;
599
600         // 2 channels of AES/EBU is present if a 1x or 2x sample rate is in
601         // use
602         if (sample_rate <= 96000)
603                 size += 2*3;
604
605         // 2 channels of (coax) SPDIF is present for 1x or 2x sample rates so
606         // long as the optical mode is not TOSLINK.  If the optical mode is 
607         // TOSLINK the coax SPDIF channels are replaced by optical TOSLINK   
608         // channels.  Thus between these options we always have an addition 
609         // 2 channels here for 1x or 2x sample rates regardless of the optical
610         // mode.
611         if (sample_rate <= 96000)
612                 size += 2*3;
613
614         // ADAT channels 1-4 are present for 1x or 2x sample rates so long
615         // as the optical mode is ADAT.
616         if (sample_rate<=96000 && optical_mode==MOTUFW_OPTICAL_MODE_ADAT)
617                 size += 4*3;
618
619         // ADAT channels 5-8 are present for 1x sample rates so long as the
620         // optical mode is ADAT.
621         if (sample_rate<=48000 && optical_mode==MOTUFW_OPTICAL_MODE_ADAT)
622                 size += 4*3;
623
624         // When 1x or 2x sample rate is active there are an additional
625         // 2 channels sent in an event.  For capture it is a Mix1 return,
626         // while for playback it is a separate headphone mix.
627         if (sample_rate<=96000)
628                 size += 2*3;
629
630         // Finally round size up to the next quadlet boundary
631         return ((size+3)/4)*4;
632 }
633 /* ======================================================================= */
634
635 bool MotuDevice::addPort(FreebobStreaming::StreamProcessor *s_processor,
636   char *name, enum FreebobStreaming::Port::E_Direction direction,
637   int position, int size) {
638 /*
639  * Internal helper function to add a MOTU port to a given stream processor.
640  * This just saves the unnecessary replication of what is essentially
641  * boilerplate code.  Note that the port name is freed by this function
642  * prior to exit.
643  */
644 FreebobStreaming::Port *p=NULL;
645
646         p = new FreebobStreaming::MotuAudioPort(name, direction, position, size);
647
648         if (!p) {
649                 debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n",name);
650         } else {
651                 if (!s_processor->addPort(p)) {
652                         debugWarning("Could not register port with stream processor\n");
653                         free(name);
654                         return false;
655                 } else {
656                         debugOutput(DEBUG_LEVEL_VERBOSE, "Added port %s\n",name);
657                 }
658                 p->enable();
659         }
660         free(name);
661         return true;
662 }
663 /* ======================================================================= */
664
665 bool MotuDevice::addDirPorts(
666   enum FreebobStreaming::Port::E_Direction direction,
667   unsigned int sample_rate, unsigned int optical_mode) {
668 /*
669  * Internal helper method: adds all required ports for the given direction
670  * based on the indicated sample rate and optical mode.
671  *
672  * Notes: currently ports are not created if they are disabled due to sample
673  * rate or optical mode.  However, it might be better to unconditionally
674  * create all ports and just disable those which are not active.
675  */
676 const char *mode_str = direction==FreebobStreaming::Port::E_Capture?"cap":"pbk";
677 const char *aux_str = direction==FreebobStreaming::Port::E_Capture?"Mix1":"Phones";
678 FreebobStreaming::StreamProcessor *s_processor;
679 unsigned int i, ofs;
680 char *buff;
681
682         if (direction == FreebobStreaming::Port::E_Capture) {
683                 s_processor = m_receiveProcessor;
684         } else {
685                 s_processor = m_transmitProcessor;
686         }
687         // Offset into an event's data of the first audio data
688         ofs = 10;
689
690         // Add ports for the Mix1 return / Phones send which is present for
691         // 1x and 2x sampling rates.
692         if (sample_rate<=96000) {
693                 for (i=0; i<2; i++, ofs+=3) {
694                         asprintf(&buff,"dev%d_%s_%s-%c", m_id, mode_str,
695                           aux_str, i==0?'L':'R');
696                         if (!addPort(s_processor, buff, direction, ofs, 0))
697                                 return false;
698                 }
699         }
700
701         // Unconditionally add the 8 analog capture ports since they are
702         // always present no matter what the device configuration is.
703         for (i=0; i<8; i++, ofs+=3) {
704                 asprintf(&buff,"dev%d_%s_Analog%d", m_id, mode_str, i+1);
705                 if (!addPort(s_processor, buff, direction, ofs, 0))
706                         return false;
707         }
708
709         // AES/EBU ports are present for 1x and 2x sampling rates on the
710         // Traveler.  On earlier interfaces (for example, 828 MkII) this
711         // space was taken up with a separate "main out" send.
712         // FIXME: what is in this position of incoming data on an 828 MkII?
713         if (sample_rate <= 96000) {
714                 for (i=0; i<2; i++, ofs+=3) {
715                         if (m_motu_model == MOTUFW_MODEL_TRAVELER) {
716                                 asprintf(&buff,"dev%d_%s_AES/EBU%d", m_id, mode_str, i+1);
717                         } else {
718                                 if (direction == FreebobStreaming::Port::E_Capture)
719                                         asprintf(&buff,"dev%d_%s_MainOut-%c", m_id, mode_str, i==0?'L':'R');
720                                 else
721                                         asprintf(&buff,"dev%d_%s_????%d", m_id, mode_str, i+1);
722                         }
723                         if (!addPort(s_processor, buff, direction, ofs, 0))
724                                 return false;
725                 }
726         }
727
728         // SPDIF ports are present for 1x and 2x sampling rates so long
729         // as the optical mode is not TOSLINK.
730         if (sample_rate<=96000 && optical_mode!=MOTUFW_OPTICAL_MODE_TOSLINK) {
731                 for (i=0; i<2; i++, ofs+=3) {
732                         asprintf(&buff,"dev%d_%s_SPDIF%d", m_id, mode_str, i+1);
733                         if (!addPort(s_processor, buff, direction, ofs, 0))
734                                 return false;
735                 }
736         }
737
738         // TOSLINK ports are present for 1x and 2x sampling rates so long
739         // as the optical mode is set to TOSLINK.
740         if (sample_rate<=96000 && optical_mode==MOTUFW_OPTICAL_MODE_TOSLINK) {
741                 for (i=0; i<2; i++, ofs+=3) {
742                         asprintf(&buff,"dev%d_%s_TOSLINK%d", m_id, mode_str, i+1);
743                         if (!addPort(s_processor, buff, direction, ofs, 0))
744                                 return false;
745                 }
746         }
747
748         // ADAT ports 1-4 are present for 1x and 2x sampling rates so long
749         // as the optical mode is set to ADAT.
750         if (sample_rate<=96000 && optical_mode==MOTUFW_OPTICAL_MODE_ADAT) {
751                 for (i=0; i<4; i++, ofs+=3) {
752                         asprintf(&buff,"dev%d_%s_ADAT%d", m_id, mode_str, i+1);
753                         if (!addPort(s_processor, buff, direction, ofs, 0))
754                                 return false;
755                 }
756         }
757
758         // ADAT ports 5-8 are present for 1x sampling rates so long as the
759         // optical mode is set to ADAT.
760         if (sample_rate<=48000 && optical_mode==MOTUFW_OPTICAL_MODE_ADAT) {
761                 for (i=4; i<8; i++, ofs+=3) {
762                         asprintf(&buff,"dev%d_%s_ADAT%d", m_id, mode_str, i+1);
763                         if (!addPort(s_processor, buff, direction, ofs, 0))
764                                 return false;
765                 }
766         }
767
768         return true;
769 }
770 /* ======================================================================== */
771
772 unsigned int MotuDevice::ReadRegister(unsigned int reg) {
773 /*
774  * Attempts to read the requested register from the MOTU.
775  */
776
777 quadlet_t quadlet;
778 assert(m_1394Service);
779        
780   quadlet = 0;
781   // Note: 1394Service::read() expects a physical ID, not the node id
782   if (m_1394Service->read(0xffc0 | m_nodeId, MOTUFW_BASE_ADDR+reg, 4, &quadlet) < 0) {
783     debugError("Error doing motu read from register 0x%06x\n",reg);
784   }
785
786   return ntohl(quadlet);
787 }
788
789 signed int MotuDevice::WriteRegister(unsigned int reg, quadlet_t data) {
790 /*
791  * Attempts to write the given data to the requested MOTU register.
792  */
793
794   unsigned int err = 0;
795   data = htonl(data);
796
797   // Note: 1394Service::write() expects a physical ID, not the node id
798   if (m_1394Service->write(0xffc0 | m_nodeId, MOTUFW_BASE_ADDR+reg, 4, &data) < 0) {
799     err = 1;
800     debugError("Error doing motu write to register 0x%06x\n",reg);
801   }
802
803   usleep(100);
804   return (err==0)?0:-1;
805 }
806
807 }
Note: See TracBrowser for help on using the browser.