~ubuntu-branches/ubuntu/oneiric/libffado/oneiric

« back to all changes in this revision

Viewing changes to src/libstreaming/digidesign/DigidesignReceiveStreamProcessor.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Adrian Knoth
  • Date: 2011-04-02 13:50:58 UTC
  • mfrom: (8.3.1 sid)
  • Revision ID: james.westby@ubuntu.com-20110402135058-d9z81mt9m7ml1l2r
Tags: 2.0.99+svn1968-1
Imported Upstream version 2.0.99+svn1968 (Closes: #601660 #601661)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2005-2008, 2011 by Jonathan Woithe
 
3
 * Copyright (C) 2005-2008 by Pieter Palmers
 
4
 *
 
5
 * This file is part of FFADO
 
6
 * FFADO = Free Firewire (pro-)audio drivers for linux
 
7
 *
 
8
 * FFADO is based upon FreeBoB.
 
9
 *
 
10
 * This program is free software: you can redistribute it and/or modify
 
11
 * it under the terms of the GNU General Public License as published by
 
12
 * the Free Software Foundation, either version 2 of the License, or
 
13
 * (at your option) version 3 of the License.
 
14
 *
 
15
 * This program is distributed in the hope that it will be useful,
 
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
18
 * GNU General Public License for more details.
 
19
 *
 
20
 * You should have received a copy of the GNU General Public License
 
21
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
22
 *
 
23
 */
 
24
 
 
25
 
 
26
#include "libutil/float_cast.h"
 
27
 
 
28
#include "DigidesignReceiveStreamProcessor.h"
 
29
#include "DigidesignPort.h"
 
30
#include "../StreamProcessorManager.h"
 
31
#include "devicemanager.h"
 
32
 
 
33
#include "libieee1394/ieee1394service.h"
 
34
#include "libieee1394/IsoHandlerManager.h"
 
35
#include "libieee1394/cycletimer.h"
 
36
 
 
37
#include "libutil/ByteSwap.h"
 
38
 
 
39
#include <cstring>
 
40
#include <math.h>
 
41
#include <assert.h>
 
42
 
 
43
 
 
44
namespace Streaming {
 
45
 
 
46
DigidesignReceiveStreamProcessor::DigidesignReceiveStreamProcessor(FFADODevice &parent, unsigned int event_size)
 
47
    : StreamProcessor(parent, ePT_Receive)
 
48
    , m_event_size( event_size )
 
49
{
 
50
    // Add whatever else needs to be initialised.
 
51
}
 
52
 
 
53
unsigned int
 
54
DigidesignReceiveStreamProcessor::getMaxPacketSize() {
 
55
 
 
56
    // Frame rate is accessible with something like this:
 
57
    //   int framerate = m_Parent.getDeviceManager().getStreamProcessorManager().getNominalRate();
 
58
 
 
59
    // What's returned here is the maximum packet size seen at the current
 
60
    // frame rate.  This depends both on the device and its configuration,
 
61
    // and is futher complicated by the IN/OUT channel asymmetry in some
 
62
    // devices.  To avoid most of these complications, just return the
 
63
    // largest packet sizes seen by any supported Digidesign device.
 
64
 
 
65
    // Fill in the requsite details.
 
66
    return 0;
 
67
}
 
68
 
 
69
unsigned int
 
70
DigidesignReceiveStreamProcessor::getNominalFramesPerPacket() {
 
71
    // Return the number of frames per firewire iso packet.  A "frame" here is a collection
 
72
    // of a single audio sample from all active audio channels.  If this depends on the
 
73
    // sample rate, that can be obtained using something like this:
 
74
    //   int framerate = m_Parent.getDeviceManager().getStreamProcessorManager().getNominalRate();
 
75
    return 0;
 
76
}
 
77
 
 
78
bool
 
79
DigidesignReceiveStreamProcessor::prepareChild() {
 
80
    debugOutput( DEBUG_LEVEL_VERBOSE, "Preparing (%p)...\n", this);
 
81
 
 
82
    // If the receive stream processor requires that things be set up which
 
83
    // could not be done in the constructor, here is where they should be
 
84
    // done.  Return true on success, or false if the setup failed for some
 
85
    // reason.  In most cases, this method will do nothing.
 
86
    
 
87
    return true;
 
88
}
 
89
 
 
90
enum StreamProcessor::eChildReturnValue
 
91
DigidesignReceiveStreamProcessor::processPacketHeader(unsigned char *data, unsigned int length, 
 
92
                                                unsigned char tag, unsigned char sy,
 
93
                                                uint32_t pkt_ctr)
 
94
{
 
95
    // This function will be called once for each incoming packet.  It
 
96
    // should check to ensure the packet contains valid data and (if it is)
 
97
    // extract a timestamp from it.  "data" points to the iso packet's
 
98
    // contents - no assumption is made about what constitutes a "header"
 
99
    // because each device's protocol is different.  Note that the firewire
 
100
    // ISO header is not included in "data".
 
101
    //
 
102
    // The return value should be one of the eCRV_* constants.  The two
 
103
    // most commonly used here are:
 
104
    //   eCRV_Invalid = unrecognised packet.  No further processing needed.
 
105
    //   eCRV_OK = packet contains audio data and requires processing.
 
106
    //
 
107
    // The decision as to what constitutes a valid data packet depends on
 
108
    // the format of the iso packets sent by the Digidesign hardware.
 
109
    //
 
110
    // Other parameters to this function contain selected information from
 
111
    // the firewire ISO header which came with this packet:
 
112
    //   - length = length in bytes of the content pointed to by "data".
 
113
    //   - tag = the iso packet header's "tag" field.
 
114
    //   - sy = the sy field from the iso packet header.
 
115
    //   - pkt_ctr = the value of the iso timer at the time the packet was
 
116
    //     received by the PC.
 
117
    //
 
118
    // If a valid packet has been received from the Digidesign device, 
 
119
    // this method should set the object's m_last_timestamp field to the
 
120
    // timestamp of the last frame in the packet.  Determining this is
 
121
    // device specific.  Some devices embed this in the stream, while
 
122
    // others require that it be synthesised.  FFADO uses this timestamp
 
123
    // to keep the transmit stream in sync with the receive stream.
 
124
 
 
125
    // An example implementation:
 
126
    //
 
127
    // if (packet is valid) {
 
128
    //   m_last_timestamp = something useful
 
129
    //   return eCRV_OK;
 
130
    // } else {
 
131
    //   return eCRV_Invalid;
 
132
    // }
 
133
 
 
134
    return eCRV_Invalid;
 
135
}
 
136
 
 
137
enum StreamProcessor::eChildReturnValue
 
138
DigidesignReceiveStreamProcessor::processPacketData(unsigned char *data, unsigned int length) {
 
139
 
 
140
    // This method is called once per ISO packet which has been flagged as 
 
141
    // valid by processPacketHeader().  "data" points to "length" bytes
 
142
    // of data.  "data" will in general have the same content as was
 
143
    // presented to processPacketHeader().
 
144
    //
 
145
    // Conceptually this method is quite simple.  Once you know the number
 
146
    // of "events" (aka frames) in the packet - either through prior
 
147
    // knowledge or by calculation based on the packet length - one simply
 
148
    // calls the associated data buffer's writeFrames() method to get the
 
149
    // data from the iso packet and into the internal buffer.  The details
 
150
    // as to how this is done are encapsulated in later methods.
 
151
 
 
152
    // First we either calculate or obtain the number of events in the packet.
 
153
    unsigned int n_events = 0;
 
154
 
 
155
    // Call writeFrames() to process the data.  m_last_timestamp should have
 
156
    // been set up by processPacketHeader().  The pointer passed to
 
157
    // writeFrames (data in this case) should for convenience be the pointer
 
158
    // to the start of the first frame's data.  If for example the packet
 
159
    // starts with its own 8-byte packet header (as opposed to the standard
 
160
    // iso packet header which is stripped off before this method is
 
161
    // called), (data+8) would be supplied instead.
 
162
    if(m_data_buffer->writeFrames(n_events, (char *)(data), m_last_timestamp)) {
 
163
        return eCRV_OK;
 
164
    } else {
 
165
        return eCRV_XRun;
 
166
    }
 
167
}
 
168
 
 
169
/***********************************************
 
170
 * Encoding/Decoding API                       *
 
171
 ***********************************************/
 
172
/**
 
173
 * \brief write received events to the port ringbuffers.
 
174
 */
 
175
bool DigidesignReceiveStreamProcessor::processReadBlock(char *data,
 
176
                       unsigned int nevents, unsigned int offset)
 
177
{
 
178
    // This function is called by the Encoding/Decoding engine encapsulated
 
179
    // by the call to writeFrames().  It should extract data from the "data"
 
180
    // array into the device's port ringbuffers.  A "port" in this context
 
181
    // is analogous to a jack port - one has one port for each audio channel
 
182
    // provided by the device.
 
183
    //
 
184
    // Each "port" is processed in turn.  The decodeDigidesign*() methods
 
185
    // are called to do the actual work.
 
186
    //
 
187
    // "offset" is an offset (in frames) from the start of the ring buffer
 
188
    // where the incoming data should be copied to.  "nevents" is the 
 
189
    // number of events (aka frames) which need to be processed for each 
 
190
    // port.
 
191
 
 
192
    bool no_problem=true;
 
193
 
 
194
    for ( PortVectorIterator it = m_Ports.begin();
 
195
          it != m_Ports.end();
 
196
          ++it ) {
 
197
        if((*it)->isDisabled()) {continue;};
 
198
 
 
199
        Port *port=(*it);
 
200
 
 
201
        switch(port->getPortType()) {
 
202
 
 
203
        case Port::E_Audio:
 
204
            if(decodeDigidesignEventsToPort(static_cast<DigidesignAudioPort *>(*it), (quadlet_t *)data, offset, nevents)) {
 
205
                debugWarning("Could not decode packet data to port %s\n",(*it)->getName().c_str());
 
206
                no_problem=false;
 
207
            }
 
208
            break;
 
209
        case Port::E_Midi:
 
210
             if(decodeDigidesignMidiEventsToPort(static_cast<DigidesignMidiPort *>(*it), (quadlet_t *)data, offset, nevents)) {
 
211
                 debugWarning("Could not decode packet midi data to port %s\n",(*it)->getName().c_str());
 
212
                 no_problem=false;
 
213
             }
 
214
            break;
 
215
 
 
216
        default: // ignore
 
217
            break;
 
218
        }
 
219
    }
 
220
    return no_problem;
 
221
}
 
222
 
 
223
signed int DigidesignReceiveStreamProcessor::decodeDigidesignEventsToPort(DigidesignAudioPort *p,
 
224
        quadlet_t *data, unsigned int offset, unsigned int nevents)
 
225
{
 
226
 
 
227
    // Decode "nevents" samples corresponding to the audio port "p" from the
 
228
    // device datastream "data" into each port's ringbuffer at an offset of
 
229
    // "offset" samples from the ringbuffer's origin.  Return value should
 
230
    // be 0.
 
231
    //
 
232
    // In theory the type of data handled by the ringbuffers can be
 
233
    // any one of the eADT_* settings.  This can be determined by calling
 
234
    //   m_StreamProcessorManager.getAudioDataType().
 
235
    // For use with JACK (the most common use case of FFADO) this will
 
236
    // always be StreamProcessorManager::eADT_Float, but one should at
 
237
    // least allow for the possibility of others, even if one chooses not
 
238
    // to support them yet.
 
239
    //
 
240
    // The getPosition() port method returns the "position" field of the
 
241
    // port.  This is used to describe where in the frame the channel's data
 
242
    // is to be found.  Other fields can be added to DigidesignAudioPort to
 
243
    // store other details which might be required to decode the data
 
244
    // packets.  In general "position" is about the only one normally
 
245
    // needed.  Whether "position" is in bytes, frames, or something else is
 
246
    // really determined by the contents of this method.  Choose whatever
 
247
    // is convenient.
 
248
 
 
249
    unsigned int j=0;
 
250
 
 
251
    // The following is an example implementation showing the general idea. 
 
252
    // It will need to be changed to suit the protocol of the Digidesign
 
253
    // devices.  It assumes that data is supplied by the device in packed
 
254
    // 24-bit integers in big endian format, and that the port's "position"
 
255
    // is in bytes.  Note that the m_event_size object member is assumed to
 
256
    // have been set up previous to be the event size in bytes.  If for a
 
257
    // given implementation it is more convenient to use a "signed int *"
 
258
    // for src_data one could have m_event_size measured in quadlets (32-bit
 
259
    // integers).  Again, it doesn't really matter so long as you're
 
260
    // consistent.
 
261
 
 
262
    // Use char here since a port's source address won't necessarily be
 
263
    // aligned; use of an unaligned quadlet_t may cause issues on
 
264
    // certain architectures.
 
265
    unsigned char *src_data;
 
266
    src_data = (unsigned char *)data + p->getPosition();
 
267
 
 
268
    switch(m_StreamProcessorManager.getAudioDataType()) {
 
269
        case StreamProcessorManager::eADT_Float:
 
270
            {
 
271
                const float multiplier = 1.0f / (float)(0x7FFFFF);
 
272
                float *buffer=(float *)(p->getBufferAddress());
 
273
 
 
274
                assert(nevents + offset <= p->getBufferSize());
 
275
 
 
276
                buffer+=offset;
 
277
 
 
278
                for (j = 0; j < nevents; j += 1) { // decode max nsamples
 
279
 
 
280
                    signed int v = (*src_data<<16)+(*(src_data+1)<<8)+*(src_data+2);
 
281
                    /* Sign-extend highest bit of incoming 24-bit integer */
 
282
                    if (*src_data & 0x80)
 
283
                      v |= 0xff000000;
 
284
                    *buffer = v * multiplier;
 
285
                    buffer++;
 
286
                    src_data += m_event_size;
 
287
                }
 
288
            }
 
289
            break;
 
290
 
 
291
        case StreamProcessorManager::eADT_Int24:
 
292
            {
 
293
                quadlet_t *buffer=(quadlet_t *)(p->getBufferAddress());
 
294
 
 
295
                assert(nevents + offset <= p->getBufferSize());
 
296
 
 
297
                // Offset is in frames, but each port is only a single
 
298
                // channel, so the number of frames is the same as the
 
299
                // number of quadlets to offset (assuming the port buffer
 
300
                // uses one quadlet per sample, which is the case currently).
 
301
                buffer+=offset;
 
302
 
 
303
                for(j = 0; j < nevents; j += 1) { // Decode nsamples
 
304
                    *buffer = (*src_data<<16)+(*(src_data+1)<<8)+*(src_data+2);
 
305
                    // Sign-extend highest bit of 24-bit int.
 
306
                    // This isn't strictly needed since E_Int24 is a 24-bit,
 
307
                    // but doing so shouldn't break anything and makes the data
 
308
                    // easier to deal with during debugging.
 
309
                    if (*src_data & 0x80)
 
310
                        *buffer |= 0xff000000;
 
311
 
 
312
                    buffer++;
 
313
                    src_data+=m_event_size;
 
314
                }
 
315
            }
 
316
            break;
 
317
 
 
318
        default:
 
319
            // Unsupported type.
 
320
            break;
 
321
    }
 
322
 
 
323
    return 0;
 
324
}
 
325
 
 
326
int
 
327
DigidesignReceiveStreamProcessor::decodeDigidesignMidiEventsToPort(
 
328
                      DigidesignMidiPort *p, quadlet_t *data,
 
329
                      unsigned int offset, unsigned int nevents)
 
330
{
 
331
    // As for decodeDigidesignEventsToPort() except this method
 
332
    // deals with MIDI streams.  Depending on how MIDI is sent by
 
333
    // the device, this method may be structured similarly to
 
334
    // decodeDigidesignEventsToPort() or it may be completely
 
335
    // different (as it is for MOTU devices for example).  Return
 
336
    // value should be zero.
 
337
    return 0;    
 
338
}
 
339
 
 
340
 
 
341
} // end of namespace Streaming