From: <tr...@ff...> - 2010-07-18 14:43:07
|
Author: jwoithe Date: 2010-07-18 07:42:58 -0700 (Sun, 18 Jul 2010) New Revision: 1869 Modified: trunk/libffado/src/libstreaming/rme/RmeReceiveStreamProcessor.cpp trunk/libffado/src/libstreaming/rme/RmeTransmitStreamProcessor.cpp trunk/libffado/src/rme/rme_avdevice.cpp trunk/libffado/src/rme/rme_avdevice.h Log: RME: more receive streaming changes. The resulting code has enabled the first successful audio capture from an RME firewire interface to Linux (test was done using FF400). RME: work towards getting playback working (no success yet - just silence). Modified: trunk/libffado/src/libstreaming/rme/RmeReceiveStreamProcessor.cpp =================================================================== --- trunk/libffado/src/libstreaming/rme/RmeReceiveStreamProcessor.cpp 2010-07-15 14:20:13 UTC (rev 1868) +++ trunk/libffado/src/libstreaming/rme/RmeReceiveStreamProcessor.cpp 2010-07-18 14:42:58 UTC (rev 1869) @@ -114,7 +114,7 @@ debugOutput(DEBUG_LEVEL_VERBOSE, "data packet header, len=%d\n", length); //fprintf(stderr, "recv len=%d\n", length); - if (length > 8) { + if (length > 0) { // The iso data blocks from the RMEs comprise 24-bit audio // data encoded in 32-bit integers. The LSB of the 32-bit integers // of certain channels are used for house-keeping information. @@ -237,15 +237,13 @@ { unsigned int j=0; - // Use char here since a port's source address won't necessarily be - // aligned; use of an unaligned quadlet_t may cause issues on certain - // architectures. Besides, the source (data coming directly from the - // RME) isn't structured in quadlets anyway; it consists 24-bit integers - // within 32-bit quadlets with the LSB being a housekeeping byte. + // For RME interfaces the audio data is contained in the most significant + // 24 bits of a 32-bit field. Thus it makes sense to treat the source + // data as 32 bit and simply mask/shift as necessary to isolate the + // audio data. + quadlet_t *src_data; + src_data = data + p->getPosition()/4; - unsigned char *src_data; - src_data = (unsigned char *)data + p->getPosition(); - switch(m_StreamProcessorManager.getAudioDataType()) { default: case StreamProcessorManager::eADT_Int24: @@ -261,16 +259,16 @@ buffer+=offset; for(j = 0; j < nevents; j += 1) { // Decode nsamples - *buffer = (*src_data<<16)+(*(src_data+1)<<8)+*(src_data+2); - // Sign-extend highest bit of 24-bit int. - // This isn't strictly needed since E_Int24 is a 24-bit, - // but doing so shouldn't break anything and makes the data - // easier to deal with during debugging. - if (*src_data & 0x80) + *buffer = (*src_data >> 8) & 0x00ffffff; + // Sign-extend highest bit of 24-bit int. This isn't + // strictly needed since E_Int24 is a 24-bit, but doing + // so shouldn't break anything and makes the data easier + // to deal with during debugging. + if (*src_data & 0x80000000) *buffer |= 0xff000000; buffer++; - src_data+=m_event_size; + src_data+=m_event_size/4; } } break; @@ -284,14 +282,13 @@ buffer+=offset; for(j = 0; j < nevents; j += 1) { // decode max nsamples - - signed int v = (*src_data<<16)+(*(src_data+1)<<8)+*(src_data+2); + signed int v = (*src_data >> 8) & 0x00ffffff; /* Sign-extend highest bit of incoming 24-bit integer */ - if (*src_data & 0x80) + if (*src_data & 0x80000000) v |= 0xff000000; *buffer = v * multiplier; buffer++; - src_data+=m_event_size; + src_data+=m_event_size/4; } } break; Modified: trunk/libffado/src/libstreaming/rme/RmeTransmitStreamProcessor.cpp =================================================================== --- trunk/libffado/src/libstreaming/rme/RmeTransmitStreamProcessor.cpp 2010-07-15 14:20:13 UTC (rev 1868) +++ trunk/libffado/src/libstreaming/rme/RmeTransmitStreamProcessor.cpp 2010-07-18 14:42:58 UTC (rev 1869) @@ -106,6 +106,7 @@ uint32_t pkt_ctr ) { unsigned int cycle = CYCLE_TIMER_GET_CYCLES(pkt_ctr); + signed n_events = getNominalFramesPerPacket(); // Called once per packet. Need to work out whether data should be sent // in this cycle or not and then act accordingly. Need to deal with @@ -115,7 +116,7 @@ // Do housekeeping expected for all packets, irrespective of whether // they will contain data. *sy = 0x00; - *length = 0; + *length = n_events*m_event_size; signed int fc; uint64_t presentation_time; @@ -272,8 +273,6 @@ RmeTransmitStreamProcessor::generatePacketData ( unsigned char *data, unsigned int *length) { - quadlet_t *quadlet = (quadlet_t *)data; - quadlet += 2; // skip the header // Size of a single data frame in quadlets // unsigned dbs = m_event_size / 4; @@ -282,7 +281,7 @@ // all channels plus possibly other midi and control data. signed n_events = getNominalFramesPerPacket(); - if (m_data_buffer->readFrames(n_events, (char *)(data + 8))) { + if (m_data_buffer->readFrames(n_events, (char *)(data))) { // float ticks_per_frame = m_Parent.getDeviceManager().getStreamProcessorManager().getSyncSource().getTicksPerFrame(); // for (int i=0; i < n_events; i++, quadlet += dbs) { @@ -290,14 +289,30 @@ // *quadlet = CondSwapToBus32(fullTicksToSph(ts_frame)); // } // FIXME: temporary - if (*length > 0) { - memset(data, *length, 0); - } +// if (*length > 0) { +// memset(data, *length, 0); +// } +// +// 1 kHz tone into ch7 (phones L) for testing +{ +float ticks_per_frame = m_Parent.getDeviceManager().getStreamProcessorManager().getSyncSource().getTicksPerFrame(); + signed int i, int_tpf = lrintf(ticks_per_frame); + quadlet_t *sample = (quadlet_t *)data + 6; + for (i=0; i<n_events; i++, sample+=m_event_size/4) { + static signed int a_cx = 0; + signed int val = lrintf(0x7fffff*sin((1000.0*2.0*M_PI/24576000.0)*a_cx)); + *sample = val << 8; + if ((a_cx+=int_tpf) >= 24576000) { + a_cx -= 24576000; + } + } +} + return eCRV_OK; } else { - // FIMXE: debugOutput() for initial testing only + // FIXME: debugOutput() for initial testing only debugOutput(DEBUG_LEVEL_VERBOSE, "readFrames() failure\n"); return eCRV_XRun; } @@ -408,7 +423,7 @@ /* Assume the packet will have audio data. If it turns out we need an empty packet * the length will be overridden by fillNoDataPacketHeader(). */ - *length = n_events*m_event_size + 8; + *length = n_events*m_event_size; uint64_t presentation_time; unsigned int presentation_cycle; @@ -468,27 +483,9 @@ unsigned char *data, unsigned int *length ) { // Simply set all audio data to zero since that's what's meant by - // a "silent" packet. Note that m_event_size is in bytes. + // a "silent" packet. + memset(data, 0, *length); - quadlet_t *quadlet = (quadlet_t *)data; - quadlet += 2; // skip the header - // Size of a single data frame in quadlets - unsigned dbs = m_event_size / 4; - - // The number of events per packet expected by the RME is solely - // dependent on the current sample rate. An 'event' is one sample from - // all channels plus possibly other midi and control data. - signed n_events = getNominalFramesPerPacket(); - - memset(quadlet, 0, n_events*m_event_size); -// float ticks_per_frame = m_Parent.getDeviceManager().getStreamProcessorManager().getSyncSource().getTicksPerFrame(); - - // Set up each frames's SPH. - for (int i=0; i < n_events; i++, quadlet += dbs) { -// int64_t ts_frame = addTicks(m_last_timestamp, (unsigned int)lrintf(i * ticks_per_frame)); -// FIXME: -// *quadlet = CondSwapToBus32(fullTicksToSph(ts_frame)); - } return eCRV_OK; } @@ -505,32 +502,13 @@ // all channels plus possibly other midi and control data. signed n_events = getNominalFramesPerPacket(); - // construct the packet CIP-like header. Even if this is a data-less - // packet the dbs field is still set as if there were data blocks - // present. For data-less packets the dbc is the same as the previously - // transmitted block. -// *quadlet = CondSwapToBus32(0x00000400 | ((m_Parent.get1394Service().getLocalNodeId()&0x3f)<<24) | m_tx_dbc | (dbs<<16)); -// quadlet++; -// *quadlet = CondSwapToBus32(0x8222ffff); -// quadlet++; return n_events; } unsigned int RmeTransmitStreamProcessor::fillNoDataPacketHeader ( quadlet_t *data, unsigned int* length ) { -// quadlet_t *quadlet = (quadlet_t *)data; - // Size of a single data frame in quadlets. -// unsigned dbs = m_event_size / 4; - // construct the packet CIP-like header. Even if this is a data-less - // packet the dbs field is still set as if there were data blocks - // present. For data-less packets the dbc is the same as the previously - // transmitted block. -// *quadlet = CondSwapToBus32(0x00000400 | ((m_Parent.get1394Service().getLocalNodeId()&0x3f)<<24) | m_tx_dbc | (dbs<<16)); -// quadlet++; -// *quadlet = CondSwapToBus32(0x8222ffff); -// quadlet++; - *length = 8; + *length = 0; return 0; } @@ -546,14 +524,7 @@ bool RmeTransmitStreamProcessor::processWriteBlock(char *data, unsigned int nevents, unsigned int offset) { bool no_problem=true; - unsigned int i; - // Start with MIDI and control streams all zeroed. Due to the sparce nature - // of these streams it is best to simply fill them in on an as-needs basis. - for (i=0; i<nevents; i++) { - memset(data+4+i*m_event_size, 0x00, 6); - } - for ( PortVectorIterator it = m_Ports.begin(); it != m_Ports.end(); ++it ) { @@ -639,13 +610,8 @@ unsigned int j=0; - // Use char here since the target address won't necessarily be - // aligned; use of an unaligned quadlet_t may cause issues on certain - // architectures. Besides, the target (data going directly to the RME) - // isn't structured in quadlets anyway; it mainly consists of packed - // 24-bit integers. - unsigned char *target; - target = (unsigned char *)data + p->getPosition(); + quadlet_t *target; + target = data + p->getPosition()/4; switch(m_StreamProcessorManager.getAudioDataType()) { default: @@ -662,12 +628,9 @@ buffer+=offset; for(j = 0; j < nevents; j += 1) { // Decode nsamples - *target = (*buffer >> 16) & 0xff; - *(target+1) = (*buffer >> 8) & 0xff; - *(target+2) = (*buffer) & 0xff; - + *target = (*buffer & 0x00ffffff) << 8; buffer++; - target+=m_event_size; + target+=m_event_size/4; } } break; @@ -687,12 +650,9 @@ if (unlikely(in < -1.0)) in = -1.0; #endif unsigned int v = lrintf(in * multiplier); - *target = (v >> 16) & 0xff; - *(target+1) = (v >> 8) & 0xff; - *(target+2) = v & 0xff; - + *target = (v << 8); buffer++; - target+=m_event_size; + target+=m_event_size/4; } } break; @@ -704,15 +664,15 @@ int RmeTransmitStreamProcessor::encodeSilencePortToRmeEvents(RmeAudioPort *p, quadlet_t *data, unsigned int offset, unsigned int nevents) { unsigned int j=0; - unsigned char *target = (unsigned char *)data + p->getPosition(); + quadlet_t *target = data + p->getPosition()/4; switch (m_StreamProcessorManager.getAudioDataType()) { default: case StreamProcessorManager::eADT_Int24: case StreamProcessorManager::eADT_Float: for (j = 0; j < nevents; j++) { - *target = *(target+1) = *(target+2) = 0; - target += m_event_size; + *target = 0; + target += m_event_size/4; } break; } Modified: trunk/libffado/src/rme/rme_avdevice.cpp =================================================================== --- trunk/libffado/src/rme/rme_avdevice.cpp 2010-07-15 14:20:13 UTC (rev 1868) +++ trunk/libffado/src/rme/rme_avdevice.cpp 2010-07-18 14:42:58 UTC (rev 1869) @@ -36,6 +36,8 @@ #include "debugmodule/debugmodule.h" +#include "libstreaming/rme/RmePort.h" + #include "devicemanager.h" #include <string> @@ -681,6 +683,7 @@ if (!getOption("id", id)) { debugWarning("Could not retrieve id parameter, defaulting to 'dev?'\n"); } + addDirPorts(Streaming::Port::E_Capture); /* Now set up the transmit stream processor */ m_transmitProcessor = new Streaming::RmeTransmitStreamProcessor(*this, @@ -699,6 +702,7 @@ // Other things to be done: // * add ports to transmit stream processor + addDirPorts(Streaming::Port::E_Playback); return true; } @@ -762,6 +766,51 @@ return 7; } +bool +Device::addPort(Streaming::StreamProcessor *s_processor, + char *name, enum Streaming::Port::E_Direction direction, + int position, int size) { + + Streaming::Port *p; + p = new Streaming::RmeAudioPort(*s_processor, name, direction, position, size); + if (p == NULL) { + debugOutput(DEBUG_LEVEL_VERBOSE, "Skipped port %s\n",name); + } + return true; +} + +bool +Device::addDirPorts(enum Streaming::Port::E_Direction direction) { + + const char *mode_str = direction==Streaming::Port::E_Capture?"cap":"pbk"; + Streaming::StreamProcessor *s_processor; + std::string id; + char name[128]; + + if (direction == Streaming::Port::E_Capture) { + s_processor = m_receiveProcessor; + } else { + s_processor = m_transmitProcessor; + } + + id = std::string("dev?"); + if (!getOption("id", id)) { + debugWarning("Could not retrieve id parameter, defaulting to 'dev?'\n"); + } + + // Just add a few ports for initial testing + snprintf(name, sizeof(name), "%s_%s_%s", id.c_str(), mode_str, "port_0"); + addPort(s_processor, name, direction, 0, 0); + snprintf(name, sizeof(name), "%s_%s_%s", id.c_str(), mode_str, "port_1"); + addPort(s_processor, name, direction, 4, 0); + snprintf(name, sizeof(name), "%s_%s_%s", id.c_str(), mode_str, "port_6"); + addPort(s_processor, name, direction, 24, 0); + snprintf(name, sizeof(name), "%s_%s_%s", id.c_str(), mode_str, "port_7"); + addPort(s_processor, name, direction, 28, 0); + + return true; +} + unsigned int Device::readRegister(fb_nodeaddr_t reg) { Modified: trunk/libffado/src/rme/rme_avdevice.h =================================================================== --- trunk/libffado/src/rme/rme_avdevice.h 2010-07-15 14:20:13 UTC (rev 1868) +++ trunk/libffado/src/rme/rme_avdevice.h 2010-07-18 14:42:58 UTC (rev 1869) @@ -92,6 +92,11 @@ signed int getNumChannels(void) { return num_channels; }; signed int getFramesPerPacket(void); + bool addPort(Streaming::StreamProcessor *s_processor, + char *name, enum Streaming::Port::E_Direction direction, + int position, int size); + bool addDirPorts(enum Streaming::Port::E_Direction direction); + unsigned int readRegister(fb_nodeaddr_t reg); signed int readBlock(fb_nodeaddr_t reg, quadlet_t *buf, unsigned int n_quads); signed int writeRegister(fb_nodeaddr_t reg, quadlet_t data); |