Browse Source

Merge pull request #56 from flatmax/master

IIO driver for Jack2
tags/v1.9.10
Stéphane Letz 11 years ago
parent
commit
13d4d408cb
6 changed files with 2435 additions and 2114 deletions
  1. +2105
    -2104
      ChangeLog
  2. +1
    -1
      common/jack/systemdeps.h
  3. +233
    -0
      linux/iio/JackIIODriver.cpp
  4. +69
    -0
      linux/iio/JackIIODriver.h
  5. +18
    -5
      linux/wscript
  6. +9
    -4
      wscript

+ 2105
- 2104
ChangeLog
File diff suppressed because it is too large
View File


+ 1
- 1
common/jack/systemdeps.h View File

@@ -120,7 +120,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

#endif /* __APPLE__ || __linux__ || __sun__ || sun */

#if defined(__arm__)
#if defined(__arm__) || defined(__ARM__)
#undef POST_PACKED_STRUCTURE
#define POST_PACKED_STRUCTURE
#endif /* __arm__ */


+ 233
- 0
linux/iio/JackIIODriver.cpp View File

@@ -0,0 +1,233 @@
/*
Copyright (C) 2013 Matt Flax <flatmax@>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

#include "JackIIODriver.h"
#include "driver_interface.h"
#include "JackEngineControl.h"
#include "JackGraphManager.h"

#include <values.h>

#define IIO_DEFAULT_CHIP "AD7476A" ///< The default IIO recording chip to look for.
#define IIO_DEFAULT_READ_FS 1.e6 ///< The default IIO sample rate for the default chip.
#define IIO_DEFAULT_PERIOD_SIZE 2048 ///< The default period size is in the ms range
#define IIO_DEFAULT_PERIOD_COUNT 2 ///< The default number of periods
#define IIO_DEFAULT_CAPUTURE_PORT_COUNT MAXINT ///< The default number of capture ports is exceedingly big, trimmed down to a realistic size in driver_initialize
//#define IIO_SAFETY_FACTOR 2./3. ///< The default safety factor, allow consumption of this fraction of the available DMA buffer before we don't allow the driver to continue.
#define IIO_SAFETY_FACTOR 1. ///< The default safety factor, allow consumption of this fraction of the available DMA buffer before we don't allow the driver to continue.

namespace Jack {

int JackIIODriver::Attach() {
//cout<<"JackIIODriver::Attach\n";
JackAudioDriver::SetSampleRate((jack_nframes_t)IIO_DEFAULT_READ_FS);

int ret;
if ((ret=iio.enable(true))!=NO_ERROR) { // start the DMA
iio.close();
return ret;
}
return JackAudioDriver::Attach();
}

int JackIIODriver::Detach() {
//cout<<"JackIIODriver::Detach\n";
iio.enable(false); // stop the DMA
return JackAudioDriver::Detach();
}

int JackIIODriver::Read() {
//cout<<"JackIIODriver::Read\n";

if (iio.getDeviceCnt()<1) {
jack_error("JackIIODriver:: No IIO devices are present ");
return -1;
}
uint devChCnt=iio[0].getChCnt(); // the number of channels per device

jack_nframes_t nframes=data.rows()/devChCnt;
if (nframes != fEngineControl->fBufferSize)
jack_error("JackIIODriver::Read warning : Jack period size = %ld IIO period size = %ld", fEngineControl->fBufferSize, nframes);

// cout<<"processing buffer size : "<<fEngineControl->fBufferSize<<endl;
// cout<<"processing channel count : "<<fCaptureChannels<<endl;

int ret=iio.read(nframes, data); // read the data from the IIO subsystem
if (ret!=NO_ERROR)
return -1;


// Keep begin cycle time
JackDriver::CycleTakeBeginTime(); // is this necessary ?

int maxAvailChCnt=data.cols()*devChCnt;
jack_default_audio_sample_t scaleFactor=1./32768.;

if (fCaptureChannels>maxAvailChCnt)
jack_error("JackIIODriver::Read warning : Jack period size = %ld IIO period size = %ld", fEngineControl->fBufferSize, nframes);

for (int i = 0; i < fCaptureChannels; i++) {
int col=i/devChCnt; // find the column and offset to read from
int rowOffset=i%devChCnt;
if (fGraphManager->GetConnectionsNum(fCapturePortList[i]) > 0) {
jack_default_audio_sample_t *dest=GetInputBuffer(i);

for (jack_nframes_t j=0; j<nframes; j++){
// dest[j]=(float)j/(float)nframes;
dest[j]=(jack_default_audio_sample_t)(data(j*devChCnt+rowOffset, col))*scaleFactor;
// cout<<dest[j]<<'\t'<<data(j*devChCnt+rowOffset, col)<<"\t\t";
}
}
}

return 0;
}

int JackIIODriver::Write() {
// cout<<"JackIIODriver::Write\n";
JackDriver::CycleTakeEndTime(); // is this necessary ?
return 0;
}

} // end namespace Jack


#ifdef __cplusplus
extern "C"
{
#endif

SERVER_EXPORT const jack_driver_desc_t *
driver_get_descriptor () {
jack_driver_desc_t * desc;
jack_driver_desc_filler_t filler;
jack_driver_param_value_t value;

desc = jack_driver_descriptor_construct("iio", JackDriverMaster, "Linux Industrial IO backend", &filler);

strcpy(value.str, IIO_DEFAULT_CHIP);
jack_driver_descriptor_add_parameter(desc, &filler, "chip", 'C', JackDriverParamString, &value, NULL, "The name of the chip to search for in the IIO devices", NULL);

value.ui = IIO_DEFAULT_CAPUTURE_PORT_COUNT;
jack_driver_descriptor_add_parameter(desc, &filler, "capture", 'i', JackDriverParamUInt, &value, NULL, "Provide capture count (block size).", NULL);

value.ui = IIO_DEFAULT_PERIOD_SIZE;
jack_driver_descriptor_add_parameter(desc, &filler, "period", 'p', JackDriverParamUInt, &value, NULL, "Frames (samples per channel) per period", NULL);

value.ui = IIO_DEFAULT_PERIOD_COUNT;
jack_driver_descriptor_add_parameter(desc, &filler, "nperiods", 'n', JackDriverParamUInt, &value, NULL, "Number of available periods (block count)", NULL);

return desc;
}

SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params) {

// As of this implementation the IIO driver is only capture... to be expanded.

string chipName(IIO_DEFAULT_CHIP); // the default chip name to search for in the IIO devices.
float fs = IIO_DEFAULT_READ_FS; // IIO sample rate is fixed.
jack_nframes_t periodSize = IIO_DEFAULT_PERIOD_SIZE; // default block size
jack_nframes_t periodCount = IIO_DEFAULT_PERIOD_COUNT; // default block count
uint inChCnt = IIO_DEFAULT_CAPUTURE_PORT_COUNT; // The default number of physical input channels - a very large number, to be reduced.

for (const JSList *node = params; node; node = jack_slist_next (node)) {
jack_driver_param_t *param = (jack_driver_param_t *) node->data;

switch (param->character) {
case 'C': // we are specifying a new chip name
chipName = param->value.str;
break;
case 'i': // we are specifying the number of capture channels
inChCnt = param->value.ui;
break;
case 'p':
periodSize = param->value.ui;
break;
case 'n':
periodCount = param->value.ui;
break;
}
}

// create the driver which contains the IIO class
Jack::JackIIODriver* iio_driver = new Jack::JackIIODriver("system", "iio_pcm", engine, table);
if (!iio_driver) {
jack_error("\nHave you run out of memory ? I tried to create the IIO driver in memory but failed!\n");
return NULL;
}

// interrogate the available iio devices searching for the chip name
if (iio_driver->iio.findDevicesByChipName(chipName)!=NO_ERROR) { // find all devices with a particular chip which are present.
jack_error("\nThe iio driver found no devices by the name %s\n", chipName.c_str());
delete iio_driver;
return NULL;
}

if (iio_driver->iio.getDeviceCnt()<1) { // If there are no devices found by that chip name, then indicate.
jack_error("\nThe iio driver found no devices by the name %s\n", chipName.c_str());
delete iio_driver;
return NULL;
}

iio_driver->iio.printInfo(); // print out detail about the devices which were found ...

// if the available number of ports is less then the requested number, then restrict to the number of physical ports.
if (iio_driver->iio.getChCnt()<inChCnt)
inChCnt=iio_driver->iio.getChCnt();

// resize the data buffer column count to match the device count
int colCnt=(int)ceil((float)inChCnt/(float)iio_driver->iio[0].getChCnt()); // check whether we require less then the available number of channels
int ret=iio_driver->iio.getReadArray(periodSize, iio_driver->data); // resize the array to be able to read enough memory
if (ret!=NO_ERROR) {
jack_error("iio::getReadArray couldn't create the data buffer, indicating the problem.");
delete iio_driver;
return NULL;
}
if (iio_driver->data.cols()>colCnt) // resize the data columns to match the specified number of columns (channels / channels per device)
iio_driver->data.resize(iio_driver->data.rows(), colCnt);

ret=iio_driver->iio.open(periodCount, periodSize); // try to open all IIO devices
if (ret!=NO_ERROR)
delete iio_driver;
return NULL;

Jack::JackDriverClientInterface* threaded_driver = new Jack::JackThreadedDriver(iio_driver);
if (threaded_driver) {
bool capture=true, playback=false, monitor=false;
int outChCnt=0;
jack_nframes_t inputLatency = periodSize*periodCount, outputLatency=0;
// Special open for OSS driver...
if (iio_driver->Open(periodSize, periodCount, capture, playback, inChCnt, outChCnt, monitor, "iio:device", "iio:device", inputLatency, outputLatency)!=0) {
delete threaded_driver;
threaded_driver=NULL;
}
} else
jack_error("\nHave you run out of memory ? I tried to create Jack's standard threaded driver in memory but failed! The good news is that you had enough memory to create the IIO driver.\n");

if (!threaded_driver) { // handle the case that the threaded_driver was not created succ.
delete iio_driver;
iio_driver=NULL;
}

return threaded_driver;
}

#ifdef __cplusplus
}
#endif

+ 69
- 0
linux/iio/JackIIODriver.h View File

@@ -0,0 +1,69 @@
/*
Copyright (C) 2013 Matt Flax <flatmax@>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

#ifndef JACKIIODRIVER_H
#define JACKIIODRIVER_H

#include "JackAudioDriver.h"
#include "JackThreadedDriver.h"

#include <IIO/IIOMMap.H>

namespace Jack {

/** The Linux Industrial IO (IIO) subsystem driver for Jack.
Currently this driver only supports capture.
*/
class JackIIODriver : public JackAudioDriver {

public:
IIOMMap iio; ///< The actual IIO devices
Eigen::Array<unsigned short int, Eigen::Dynamic, Eigen::Dynamic> data; ///< When we grab a mmapped buffer, store it here.

/** Constructor
*/
JackIIODriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table) : JackAudioDriver(name, alias, engine, table) {
}

/** Destructor
*/
virtual ~JackIIODriver() {
}

// virtual int Process(){
//// cout<<"JackIIODriver::Process\n";
// return JackAudioDriver::Process();
// }
//
virtual int Attach(); ///< Enables the IIO system.

virtual int Detach(); ///< Disables the IIO system.

virtual int Read(); ///< Read from the IIO sysetm and load the jack buffers

virtual int Write(); ///< Not implemented.

virtual int SetBufferSize(jack_nframes_t buffer_size){
cout<<"JackIIODriver::SetBufferSize("<<buffer_size<<")\n";
return JackAudioDriver::SetBufferSize(buffer_size);
}
};

} // end of Jack namespace
#endif // JACKIIODRIVER_H

+ 18
- 5
linux/wscript View File

@@ -1,6 +1,8 @@
#! /usr/bin/env python
# encoding: utf-8

from waflib import Context

def configure(conf):
conf.check_cfg(package='alsa', atleast_version='1.0.18', args='--cflags --libs', mandatory=False)
conf.env['BUILD_DRIVER_ALSA'] = conf.is_defined('HAVE_ALSA')
@@ -11,7 +13,13 @@ def configure(conf):
conf. check_cfg(package='libffado', atleast_version='1.999.17', args='--cflags --libs', mandatory=False)
conf.env['BUILD_DRIVER_FFADO'] = conf.is_defined('HAVE_LIBFFADO')

conf.define('HAVE_PPOLL', 1 )
conf.check_cfg(package='gtkIOStream', atleast_version='1.4.0', args='--cflags --libs', mandatory=False)
conf.env['BUILD_DRIVER_IIO'] = conf.is_defined('HAVE_GTKIOSTREAM')
conf.check_cfg(package='eigen3', atleast_version='3.1.2', args='--cflags --libs', mandatory=False)
conf.env['BUILD_DRIVER_IIO'] += conf.is_defined('HAVE_EIGEN3')
conf.check_cfg(package='sox', atleast_version='14.4.0', args='--cflags --libs', mandatory=False)
conf.env['BUILD_DRIVER_IIO'] += conf.is_defined('HAVE_SOX')


def create_jack_driver_obj(bld, target, sources, uselib = None):
driver = bld(features = ['c', 'cxx', 'cxxshlib', 'cshlib'])
@@ -36,15 +44,15 @@ def build(bld):
jackd.defines = ['HAVE_CONFIG_H','SERVER_SIDE']
jackd.source = ['../common/Jackdmp.cpp']
jackd.use = ['serverlib']
if bld.env['IS_LINUX'] and bld.env['BUILD_JACKDBUS']:
jackd.source += ['../dbus/reserve.c', '../dbus/audio_reserve.c']
if bld.env['IS_LINUX'] and bld.env['BUILD_JACKDBUS']:
jackd.source += ['../dbus/reserve.c', '../dbus/audio_reserve.c']
jackd.use += ['PTHREAD', 'DL', 'RT', 'M', 'STDC++', 'DBUS-1']
else:
jackd.use += ['PTHREAD', 'DL', 'RT', 'M', 'STDC++']
jackd.target = 'jackd'
create_jack_driver_obj(bld, 'dummy', '../common/JackDummyDriver.cpp')
alsa_driver_src = [
'alsa/JackAlsaDriver.cpp',
'alsa/alsa_rawmidi.c',
@@ -74,6 +82,8 @@ def build(bld):
'firewire/JackFFADOMidiSendQueue.cpp'
]

iio_driver_src = ['iio/JackIIODriver.cpp']

if bld.env['BUILD_DRIVER_ALSA'] == True:
create_jack_driver_obj(bld, 'alsa', alsa_driver_src, ["ALSA"])
create_jack_driver_obj(bld, 'alsarawmidi', alsarawmidi_driver_src,
@@ -85,6 +95,9 @@ def build(bld):
if bld.env['BUILD_DRIVER_FFADO'] == True:
create_jack_driver_obj(bld, 'firewire', ffado_driver_src, ["LIBFFADO"])

if bld.env['BUILD_DRIVER_IIO'] == True:
create_jack_driver_obj(bld, 'iio', iio_driver_src, ["GTKIOSTREAM", "EIGEN3"])

create_jack_driver_obj(bld, 'net', '../common/JackNetDriver.cpp')

create_jack_driver_obj(bld, 'loopback', '../common/JackLoopbackDriver.cpp')


+ 9
- 4
wscript View File

@@ -83,6 +83,7 @@ def options(opt):
opt.add_option('--firewire', action='store_true', default=False, help='Enable FireWire driver (FFADO)')
opt.add_option('--freebob', action='store_true', default=False, help='Enable FreeBob driver')
opt.add_option('--alsa', action='store_true', default=False, help='Enable ALSA driver')
opt.add_option('--iio', action='store_true', default=False, help='Enable IIO driver')
opt.add_option('--autostart', type='string', default="default", help='Autostart method. Possible values: "default", "classic", "dbus", "none"')
opt.add_option('--portaudio', action='store_true', default=False, help='Enable Portaudio driver')
opt.add_option('--winmme', action='store_true', default=False, help='Enable WinMME driver')
@@ -136,7 +137,7 @@ def configure(conf):
conf.check_tool('compiler_cc')
conf.env.append_unique('CCDEFINES', '_POSIX')
conf.env.append_unique('CXXDEFINES', '_POSIX')
conf.env.append_unique('CXXFLAGS', '-Wall')
conf.env.append_unique('CFLAGS', '-Wall')

@@ -149,9 +150,12 @@ def configure(conf):
conf.fatal('FreeBob driver was explicitly requested but cannot be built')
if Options.options.firewire and not conf.env['BUILD_DRIVER_FFADO']:
conf.fatal('FFADO driver was explicitly requested but cannot be built')
if Options.options.iio and not conf.env['BUILD_DRIVER_IIO']:
conf.fatal('IIO driver was explicitly requested but cannot be built')
conf.env['BUILD_DRIVER_ALSA'] = Options.options.alsa
conf.env['BUILD_DRIVER_FFADO'] = Options.options.firewire
conf.env['BUILD_DRIVER_FREEBOB'] = Options.options.freebob
conf.env['BUILD_DRIVER_IIO'] = Options.options.iio
if conf.env['IS_WINDOWS']:
conf.sub_config('windows')
if Options.options.portaudio and not conf.env['BUILD_DRIVER_PORTAUDIO']:
@@ -319,7 +323,7 @@ def configure(conf):

print("Build with a maximum of %d JACK clients" % Options.options.clients)
print("Build with a maximum of %d ports per application" % Options.options.application_ports)
display_msg("Install prefix", conf.env['PREFIX'], 'CYAN')
display_msg("Library directory", conf.all_envs[""]['LIBDIR'], 'CYAN')
if conf.env['BUILD_WITH_32_64'] == True:
@@ -350,11 +354,12 @@ def configure(conf):
display_feature('Build with ALSA support', conf.env['BUILD_DRIVER_ALSA'] == True)
display_feature('Build with FireWire (FreeBob) support', conf.env['BUILD_DRIVER_FREEBOB'] == True)
display_feature('Build with FireWire (FFADO) support', conf.env['BUILD_DRIVER_FFADO'] == True)
display_feature('Build with IIO support', conf.env['BUILD_DRIVER_IIO'] == True)

if conf.env['IS_WINDOWS']:
display_feature('Build with WinMME support', conf.env['BUILD_DRIVER_WINMME'] == True)
display_feature('Build with Portaudio support', conf.env['BUILD_DRIVER_PORTAUDIO'] == True)
if conf.env['BUILD_JACKDBUS'] == True:
display_msg('D-Bus service install directory', conf.env['DBUS_SERVICES_DIR'], 'CYAN')
#display_msg('Settings persistence', xxx)
@@ -407,7 +412,7 @@ def build(bld):
bld.add_subdirs('man')
if bld.env['BUILD_JACKDBUS'] == True:
bld.add_subdirs('dbus')
if bld.env['IS_MACOSX']:
bld.add_subdirs('macosx')
bld.add_subdirs('example-clients')


Loading…
Cancel
Save