Logo Search packages:      
Sourcecode: jack-audio-connection-kit version File versions  Download package

portaudio_driver.c

/* -*- mode: c; c-file-style: "bsd"; -*- */
/*
    Copyright  Grame 2003

    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.

    Grame Research Laboratory, 9, rue du Garet 69001 Lyon - France
    grame@rd.grame.fr
    
    02-09-03 : Modify jack port naming : add the name of the used driver
               Add the -n option to load a specific driver using it's name
    04-09-03 : Correct bug in -n option management : input and ouput have to be treated separately
    08-09-03 : More robust driver loading code : new portaudio_load_default and portaudio_load_driver functions.
    24-09-03 : Does not tries to load default device if the required one is not found, returns and error.
    14-10-03 : After jack port name size extension, does not use fixed length for CoreAudio driver name anymore
      09-01-04 : Handle different value for channel in and channel out (using -i and -o)
      12-01-04 : Connect port names (inverse "in" and "out")      
      13-01-04 : Correct the length of jack port : use JACK_PORT_NAME_SIZE
      22-03-04 : Remove jack_init_time, rename input and ouput ports using "capture" and "playback" 
    10-11-04 : S. Letz: Add management of -I option for use with JackPilot.
      17-11-04 : S. Letz: Better debug code.
      03-02-05 : S. Letz: fix several driver detection bugs on OSX.
      06-08-05 : S.Letz: Remove the "-I" parameter, change the semantic of "-n" parameter on OSX : -n (driver name) now correctly uses the PropertyDeviceUID
                    (persistent accross reboot...) as the identifier for the used coreaudio driver.

*/

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>

#include <jack/engine.h>
#include "portaudio_driver.h"

#ifdef JACK_USE_MACH_THREADS

#include <CoreAudio/CoreAudio.h>

static OSStatus get_device_name_from_id(AudioDeviceID id, char name[60])
{
    UInt32 size = sizeof(char) * 60;
      OSStatus stat = AudioDeviceGetProperty(id, 0, false,
                                 kAudioDevicePropertyDeviceName,
                                 &size,
                                 &name[0]);
    return stat;
}

static OSStatus get_device_id_from_num(int i, AudioDeviceID * id)
{
    OSStatus theStatus;
    UInt32 theSize;
    int nDevices;
    AudioDeviceID *theDeviceList;

    theStatus =
      AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices,
                             &theSize, NULL);
    nDevices = theSize / sizeof(AudioDeviceID);
    theDeviceList =
      (AudioDeviceID *) malloc(nDevices * sizeof(AudioDeviceID));
    theStatus =
      AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &theSize,
                         theDeviceList);

    *id = theDeviceList[i];
    return theStatus;
}

static OSStatus get_device_id_from_uid(char* UID, AudioDeviceID* id)
{
      UInt32 size = sizeof(AudioValueTranslation);
      CFStringRef inIUD = CFStringCreateWithCString(NULL, UID, CFStringGetSystemEncoding());
      AudioValueTranslation value = { &inIUD, sizeof(CFStringRef), id, sizeof(AudioDeviceID) };
      if (inIUD == NULL) {
            return kAudioHardwareUnspecifiedError;
      } else {
            OSStatus res = AudioHardwareGetProperty(kAudioHardwarePropertyDeviceForUID, &size, &value);
            CFRelease(inIUD);
            return res;
      }
}

#else
typedef unsigned int AudioDeviceID;
#endif

#define PRINTDEBUG 1

void PALog(char *fmt, ...)
{
#ifdef PRINTDEBUG
    va_list ap;
    va_start(ap, fmt);
    fprintf(stderr, "JCA: ");
    vfprintf(stderr, fmt, ap);
    va_end(ap);
#endif
}

static int
paCallback(void *inputBuffer, void *outputBuffer,
                             unsigned long framesPerBuffer,
                             PaTimestamp outTime, void *userData)
{
      portaudio_driver_t * driver = (portaudio_driver_t*)userData;

      driver->inPortAudio = (float*)inputBuffer;
      driver->outPortAudio = (float*)outputBuffer;
      driver->last_wait_ust = jack_get_microseconds();
      return driver->engine->run_cycle(driver->engine, framesPerBuffer, 0);
}

static int
portaudio_driver_attach (portaudio_driver_t *driver, jack_engine_t *engine)
{
      jack_port_t *port;
      int port_flags;
      channel_t chn;
      char buf[JACK_PORT_NAME_SIZE];
            
      driver->engine = engine;
      
      driver->engine->set_buffer_size (engine, driver->frames_per_cycle);
      driver->engine->set_sample_rate (engine, driver->frame_rate);
      
      port_flags = JackPortIsOutput|JackPortIsPhysical|JackPortIsTerminal;

      /*
      if (driver->has_hw_monitoring) {
                  port_flags |= JackPortCanMonitor;
      }
      */

      for (chn = 0; chn < driver->capture_nchannels; chn++) {
                  //snprintf (buf, sizeof(buf) - 1, "%s:capture%lu", driver->driver_name, chn+1);
                  snprintf (buf, sizeof(buf) - 1, "%s:out%lu", driver->driver_name, chn+1);

                  if ((port = jack_port_register (driver->client, buf, JACK_DEFAULT_AUDIO_TYPE, port_flags, 0)) == NULL) {
                              jack_error ("portaudio: cannot register port for %s", buf);
                              break;
                  }

                  /* XXX fix this so that it can handle: systemic (external) latency
                  */

                  jack_port_set_latency (port, driver->frames_per_cycle);
                  driver->capture_ports = jack_slist_append (driver->capture_ports, port);
      }
      
      port_flags = JackPortIsInput|JackPortIsPhysical|JackPortIsTerminal;

      for (chn = 0; chn < driver->playback_nchannels; chn++) {
                  //snprintf (buf, sizeof(buf) - 1, "%s:playback%lu", driver->driver_name, chn+1);
                  snprintf (buf, sizeof(buf) - 1, "%s:in%lu", driver->driver_name, chn+1);

                  if ((port = jack_port_register (driver->client, buf, JACK_DEFAULT_AUDIO_TYPE, port_flags, 0)) == NULL) {
                              jack_error ("portaudio: cannot register port for %s", buf);
                              break;
                  }
                  
                  /* XXX fix this so that it can handle: systemic (external) latency
                  */
      
                  jack_port_set_latency (port, driver->frames_per_cycle);
                  driver->playback_ports = jack_slist_append (driver->playback_ports, port);
      }

      jack_activate (driver->client);
      return 0; 
}

static int
portaudio_driver_detach (portaudio_driver_t *driver, jack_engine_t *engine)
{
      JSList *node;

      if (driver->engine == 0) {
                  return -1;
      }

      for (node = driver->capture_ports; node; node = jack_slist_next (node)) {
                  jack_port_unregister (driver->client, ((jack_port_t *) node->data));
      }

      jack_slist_free (driver->capture_ports);
      driver->capture_ports = 0;
                  
      for (node = driver->playback_ports; node; node = jack_slist_next (node)) {
                  jack_port_unregister (driver->client, ((jack_port_t *) node->data));
      }

      jack_slist_free (driver->playback_ports);
      driver->playback_ports = 0;
      
      driver->engine = 0;
      return 0; 
}

static int
portaudio_driver_null_cycle (portaudio_driver_t* driver, jack_nframes_t nframes)
{
      memset(driver->outPortAudio, 0, (driver->playback_nchannels * nframes * sizeof(float)));
      return 0;
}

static int
portaudio_driver_read (portaudio_driver_t *driver, jack_nframes_t nframes)
{
      jack_default_audio_sample_t *buf;
      channel_t chn;
      jack_port_t *port;
      JSList *node;
      int i;

      for (chn = 0, node = driver->capture_ports; node; node = jack_slist_next (node), chn++) {
                  
                  port = (jack_port_t *)node->data;
                  
                  if (jack_port_connected (port) && (driver->inPortAudio != NULL)) {
                        int channels = driver->capture_nchannels;
                        float* in = driver->inPortAudio;
                        buf = jack_port_get_buffer (port, nframes); 
                        for (i = 0; i< nframes; i++) buf[i] = in[channels*i+chn];
                  }

      }
   
      driver->engine->transport_cycle_start (driver->engine,
                                 jack_get_microseconds ());
      return 0;
}          


static int
portaudio_driver_write (portaudio_driver_t *driver, jack_nframes_t nframes)
{
      jack_default_audio_sample_t *buf;
      channel_t chn;
      jack_port_t *port;
      JSList *node;
      int i,bytes = nframes*sizeof(float);
      
      /* Clear in case of nothing is connected */
      memset(driver->outPortAudio, 0, driver->playback_nchannels*bytes);
                  
      for (chn = 0, node = driver->playback_ports; node; node = jack_slist_next (node), chn++) {
                  
                  port = (jack_port_t *)node->data;
                  
                  if (jack_port_connected (port) && (driver->outPortAudio != NULL)) {
                              int channels = driver->playback_nchannels;
                              float* out = driver->outPortAudio;
                              buf = jack_port_get_buffer (port, nframes);
                              for (i = 0; i< nframes; i++) out[channels*i+chn] = buf[i];
                  }
      }
      
      return 0;
}

static int
portaudio_driver_audio_start (portaudio_driver_t *driver)
{
      PaError err = Pa_StartStream(driver->stream);
      return (err != paNoError) ? -1 : 0;
}

static int
portaudio_driver_audio_stop (portaudio_driver_t *driver)
{
      PaError err = Pa_StopStream(driver->stream);
      return (err != paNoError) ? -1 : 0;
}

static int
portaudio_driver_set_parameters (portaudio_driver_t* driver,
                           jack_nframes_t nframes,
                           jack_nframes_t rate)
{
      int capturing = driver->capturing;
      int playing = driver->playing;

      int err = Pa_OpenStream(
            &driver->stream,
            ((capturing) ? Pa_GetDefaultInputDeviceID() : paNoDevice),  
            ((capturing) ? driver->capture_nchannels : 0),             
            paFloat32,        /* 32-bit float input */
            NULL,
            ((playing) ? Pa_GetDefaultOutputDeviceID() : paNoDevice),
            ((playing) ?  driver->playback_nchannels : 0),        
            paFloat32,        /* 32-bit float output */
            NULL,
            rate,             /* sample rate */
            nframes,          /* frames per buffer */
            0,                      /* number of buffers = default min */
            paClipOff,        /* we won't output out of
                                    * range samples so don't
                                    * bother clipping them */
            paCallback,
            driver);
    
      if (err == paNoError) {
        
            driver->period_usecs = (((float) driver->frames_per_cycle)
                              / driver->frame_rate) * 1000000.0f;
            driver->frame_rate = rate;
            driver->frames_per_cycle = nframes;

            /* tell engine about buffer size */
            if (driver->engine) {
                  driver->engine->set_buffer_size (
                        driver->engine, driver->frames_per_cycle);
            }
            return 0;

      } else { 

            // JOQ: this driver is dead.  How do we terminate it?
            Pa_Terminate();
            fprintf(stderr, "Unable to set portaudio parameters\n"); 
            fprintf(stderr, "Error number: %d\n", err);
            fprintf(stderr, "Error message: %s\n", Pa_GetErrorText(err));
            return EIO;
      }
}

static int
portaudio_driver_reset_parameters (portaudio_driver_t* driver,
                           jack_nframes_t nframes,
                           jack_nframes_t rate)
{
      if (!jack_power_of_two(nframes)) {
            fprintf (stderr, "PA: frames must be a power of two "
                   "(64, 512, 1024, ...)\n");
            return EINVAL;
      }

      Pa_CloseStream(driver->stream);
      return portaudio_driver_set_parameters (driver, nframes, rate);
}

static int
portaudio_driver_bufsize (portaudio_driver_t* driver, jack_nframes_t nframes)
{
      int rc;

      /* This gets called from the engine server thread, so it must
       * be serialized with the driver thread.  Stopping the audio
       * also stops that thread. */

      if (portaudio_driver_audio_stop (driver)) {
            jack_error ("PA: cannot stop to set buffer size");
            return EIO;
      }

      rc = portaudio_driver_reset_parameters (driver, nframes,
                                    driver->frame_rate);

      if (portaudio_driver_audio_start (driver)) {
            jack_error ("PA: cannot restart after setting buffer size");
            rc = EIO;
      }

      return rc;
}

//== instance creation/destruction =============================================

static int portaudio_load_default (portaudio_driver_t *driver, 
                                    int numDevices, 
                                    int capturing, 
                                    int playing, 
                                    int* inputDeviceID,
                                    int* outputDeviceID)
{
    const PaDeviceInfo *pdi;
    int i,j;
    int found = 0;
    
    PALog("Look for default driver\n");
    
    *inputDeviceID = Pa_GetDefaultInputDeviceID();
    *outputDeviceID = Pa_GetDefaultOutputDeviceID();

    for(i=0; i<numDevices; i++)
    {
        pdi = Pa_GetDeviceInfo(i);
        PALog("---------------------------------------------- #%d\n", i);
        
        if (i == Pa_GetDefaultInputDeviceID()) {
            driver->capture_nchannels = (capturing) ? pdi->maxInputChannels : 0;
            strcpy (driver->driver_name,pdi->name);
            found = 1;
        }
        
        if (i == Pa_GetDefaultOutputDeviceID()){
            driver->playback_nchannels = (playing) ? pdi->maxOutputChannels : 0;
            strcpy (driver->driver_name,pdi->name);
            found = 1;
        }
        
        PALog("\nName         = %s\n", pdi->name);
        PALog("Max Inputs = %d ", pdi->maxInputChannels);
        PALog("Max Outputs = %d\n", pdi->maxOutputChannels);
        if( pdi->numSampleRates == -1 ){
            PALog("Sample Rate Range = %f to %f\n", pdi->sampleRates[0], pdi->sampleRates[1]);
        }else{
            PALog("Sample Rates =");
            for(j=0; j<pdi->numSampleRates; j++){
                PALog(" %8.2f,", pdi->sampleRates[j]);
            }
            PALog("\n");
        }
        
        PALog("Native Sample Formats = ");
        if (pdi->nativeSampleFormats & paInt8)        PALog("paInt8, ");
        if (pdi->nativeSampleFormats & paUInt8)       PALog("paUInt8, ");
        if (pdi->nativeSampleFormats & paInt16)       PALog("paInt16, ");
        if (pdi->nativeSampleFormats & paInt32)       PALog("paInt32, ");
        if (pdi->nativeSampleFormats & paFloat32)     PALog("paFloat32, ");
        if (pdi->nativeSampleFormats & paInt24)       PALog("paInt24, ");
        if (pdi->nativeSampleFormats & paPackedInt24) PALog("paPackedInt24, ");
        PALog("\n");
    }
    
    return found;
}

static int portaudio_load_driver (portaudio_driver_t *driver, 
                                    int numDevices, 
                                    int capturing, 
                                    int playing, 
                                    int* inputDeviceID,
                                    int* outputDeviceID,
                                    char* driver_name)
{
    const PaDeviceInfo *pdi;
    int found = 0;
    int i,j;
    
    PALog("Look for %s driver\n",driver_name);
      
    for(i=0; i<numDevices; i++)
    {
        pdi = Pa_GetDeviceInfo(i);
        PALog("---------------------------------------------- #%d\n", i);
        
            // compare the first character
            if (strncmp (driver_name, pdi->name,
                 JACK_DRIVER_PARAM_STRING_MAX) == 0) {
            if (pdi->maxInputChannels > 0) {
                  *inputDeviceID = i;
                  driver->capture_nchannels =
                  (capturing) ? pdi->maxInputChannels : 0;
                  strcpy(driver->driver_name,pdi->name);
                  PALog("Found input driver = %s\n", driver_name);
                  found = 1;
            }
          if (pdi->maxOutputChannels > 0) {
                  *outputDeviceID = i;
                  driver->playback_nchannels =
                  (playing) ? pdi->maxOutputChannels : 0;
                  strcpy (driver->driver_name,pdi->name);
                  PALog("Found output driver = %s\n", driver_name);
                  found = 1;
            } else {
                  PALog("Found driver without input or ouput = %s\n",
                   driver_name);
            }
        }
                        
        PALog("\nName         = %s\n", pdi->name);
        PALog("Max Inputs = %d ", pdi->maxInputChannels);
        PALog("Max Outputs = %d\n", pdi->maxOutputChannels);
        if( pdi->numSampleRates == -1 ){
            PALog("Sample Rate Range = %f to %f\n", pdi->sampleRates[0],
                  pdi->sampleRates[1]);
        }else{
            PALog("Sample Rates =");
            for(j=0; j<pdi->numSampleRates; j++){
                PALog(" %8.2f,", pdi->sampleRates[j]);
            }
            PALog("\n");
        }
        
        PALog("Native Sample Formats = ");
        if (pdi->nativeSampleFormats & paInt8)        PALog("paInt8, ");
        if (pdi->nativeSampleFormats & paUInt8)       PALog("paUInt8, ");
        if (pdi->nativeSampleFormats & paInt16)       PALog("paInt16, ");
        if (pdi->nativeSampleFormats & paInt32)       PALog("paInt32, ");
        if (pdi->nativeSampleFormats & paFloat32)     PALog("paFloat32, ");
        if (pdi->nativeSampleFormats & paInt24)       PALog("paInt24, ");
        if (pdi->nativeSampleFormats & paPackedInt24) PALog("paPackedInt24, ");
        PALog("\n");
    }
    
    return found;
}

/** create a new driver instance
 */
static jack_driver_t *
portaudio_driver_new (char *name, 
                        jack_client_t* client,
                        jack_nframes_t frames_per_cycle,
                        jack_nframes_t rate,
                        int capturing,
                        int playing,
                        int chan_in, 
                        int chan_out,
                        DitherAlgorithm dither,
                        char* driver_name)
{
      portaudio_driver_t *driver;
      PaError err = paNoError;
      int numDevices;
      int inputDeviceID,outputDeviceID;
      int found;
      
      PALog("portaudio driver version : %d\n", kVersion);
      PALog("creating portaudio driver ... %" PRIu32 "|%" PRIu32 "\n",
            frames_per_cycle, rate);

      driver = (portaudio_driver_t *) calloc (1, sizeof (portaudio_driver_t));

      jack_driver_init ((jack_driver_t *) driver);

      if (!jack_power_of_two(frames_per_cycle)) {
            fprintf (stderr, "PA: -p must be a power of two.\n");
            goto error;
      }

      driver->frames_per_cycle = frames_per_cycle;
      driver->frame_rate = rate;
      driver->capturing = capturing;
      driver->playing = playing;

      driver->attach = (JackDriverAttachFunction) portaudio_driver_attach;
      driver->detach = (JackDriverDetachFunction) portaudio_driver_detach;
      driver->read = (JackDriverReadFunction) portaudio_driver_read;
      driver->write = (JackDriverReadFunction) portaudio_driver_write;
      driver->null_cycle = (JackDriverNullCycleFunction) portaudio_driver_null_cycle;
      driver->bufsize = (JackDriverBufSizeFunction) portaudio_driver_bufsize;
      driver->start = (JackDriverStartFunction) portaudio_driver_audio_start;
      driver->stop = (JackDriverStopFunction) portaudio_driver_audio_stop;
      driver->stream = NULL;

#ifdef JACK_USE_MACH_THREADS  
      AudioDeviceID device_id;
      if (driver_name) {
            if (get_device_id_from_uid(driver_name, &device_id) != noErr)
                  goto error;
            if (get_device_name_from_id(device_id, driver->driver_name) != noErr)
                  goto error;
      } else {
            if (get_device_id_from_num(0, &device_id) != noErr)
                  goto error; 
            if (get_device_name_from_id(device_id, driver->driver_name) != noErr)
                  goto error;
      }
#endif
       
      err = Pa_Initialize();
      PALog("Pa_Initialize OK \n");
      
      PALog("Driver name required %s\n",driver->driver_name);
      numDevices = Pa_CountDevices();
      
      if( numDevices < 0 ){
            PALog("ERROR: Pa_CountDevices returned 0x%x\n", numDevices);
            err = numDevices;
            goto error;
      }
      
      PALog("Number of devices = %d\n", numDevices);

      if (strcmp(driver->driver_name,"") == 0) {
            found = portaudio_load_default(driver,numDevices,capturing,playing,&inputDeviceID,&outputDeviceID);
            if (!found) {
                  PALog("ERROR : default driver has not been found\n");
                  err = paHostError;
                  goto error;
            }
      }else{
            found = portaudio_load_driver(driver,numDevices,capturing,playing,&inputDeviceID,&outputDeviceID,driver->driver_name);
            if (!found) {
                   PALog("ERROR : driver %s has not been found \n",driver->driver_name);
                   err = paHostError;
                   goto error;
            }
      }

      if (err != paNoError) goto error;
      
      PALog("Pa_GetDefaultOutputDeviceID() %ld\n", (long)Pa_GetDefaultOutputDeviceID());
      PALog("Pa_GetDefaultInputDeviceID() %ld\n",  (long)Pa_GetDefaultInputDeviceID());
      
      PALog("--------------------------------------------------\n");
      PALog("CoreAudio driver %s will be loaded\n", driver->driver_name);
      PALog("inputDeviceID %ld\n",  (long)inputDeviceID);
      PALog("outputDeviceID %ld\n",  (long)outputDeviceID);
      PALog("driver->capture_nchannels %ld\n", driver->capture_nchannels);
      PALog("driver->playback_nchannels %ld\n", driver->playback_nchannels);
      
      PALog("chan_in, chan_out %ld %ld\n",  (long)chan_in,  (long)chan_out);
        
      if (chan_in > 0) 
            driver->capture_nchannels = (driver->capture_nchannels < chan_in) ? driver->capture_nchannels : chan_in;
      
      if (chan_out > 0) 
            driver->playback_nchannels = (driver->playback_nchannels < chan_out) ? driver->playback_nchannels : chan_out;
            
      PALog("driver->capture_nchannels %ld\n", driver->capture_nchannels);
      PALog("driver->playback_nchannels %ld\n", driver->playback_nchannels);
      
      err = Pa_OpenStream(&driver->stream,
                                    ((capturing && (driver->capture_nchannels > 0)) ? inputDeviceID : paNoDevice),
                                    ((capturing) ? driver->capture_nchannels : 0),             
                                    paFloat32,  // 32 bit floating point input 
                                    NULL,
                                    ((playing && (driver->playback_nchannels > 0)) ? outputDeviceID : paNoDevice),
                                    ((playing) ? driver->playback_nchannels : 0),        
                                    paFloat32,  // 32 bit floating point output 
                                    NULL,
                                    rate,
                                    frames_per_cycle,            // frames per buffer 
                                    0,              // number of buffers, if zero then use default minimum 
                                    paClipOff,      // we won't output out of range samples so don't bother clipping them 
                                    paCallback,
                                    driver);
      
      if (err != paNoError) goto error;
      
      driver->client = client; 
      driver->period_usecs = (((float) driver->frames_per_cycle) / driver->frame_rate) * 1000000.0f;
      return((jack_driver_t *) driver);

error:

      Pa_Terminate();
      fprintf(stderr, "An error occured while using the portaudio stream\n"); 
      fprintf(stderr, "Error number: %d\n", err);
      fprintf(stderr, "Error message: %s\n", Pa_GetErrorText(err));
      free(driver);
      return NULL;
}

/** free all memory allocated by a driver instance
 */
static void
portaudio_driver_delete (portaudio_driver_t *driver)
{
      /* Close PortAudio stream and terminate */
      Pa_CloseStream(driver->stream);
      Pa_Terminate();
      free(driver);
}

//== driver "plugin" interface =================================================

/* DRIVER "PLUGIN" INTERFACE */

jack_driver_desc_t *
driver_get_descriptor ()
{
      jack_driver_desc_t * desc;
      unsigned int i;
      desc = calloc (1, sizeof (jack_driver_desc_t));

      strcpy (desc->name, "portaudio");
      desc->nparams = 10;
      desc->params = calloc (desc->nparams,
                         sizeof (jack_driver_param_desc_t));

      i = 0;
      strcpy (desc->params[i].name, "channel");
      desc->params[i].character  = 'c';
      desc->params[i].type       = JackDriverParamInt;
      desc->params[i].value.ui   = 0;
      strcpy (desc->params[i].short_desc, "Maximum number of channels");
      strcpy (desc->params[i].long_desc, desc->params[i].short_desc);
      
      i++;
      strcpy (desc->params[i].name, "channelin");
      desc->params[i].character  = 'i';
      desc->params[i].type       = JackDriverParamInt;
      desc->params[i].value.ui   = 0;
      strcpy (desc->params[i].short_desc, "Maximum number of input channels");
      strcpy (desc->params[i].long_desc, desc->params[i].short_desc);

      i++;
      strcpy (desc->params[i].name, "channelout");
      desc->params[i].character  = 'o';
      desc->params[i].type       = JackDriverParamInt;
      desc->params[i].value.ui   = 0;
      strcpy (desc->params[i].short_desc, "Maximum number of ouput channels");
      strcpy (desc->params[i].long_desc, desc->params[i].short_desc);

      i++;
      strcpy (desc->params[i].name, "capture");
      desc->params[i].character  = 'C';
      desc->params[i].type       = JackDriverParamBool;
      desc->params[i].value.i    = TRUE;
      strcpy (desc->params[i].short_desc, "Whether or not to capture");
      strcpy (desc->params[i].long_desc, desc->params[i].short_desc);

      i++;
      strcpy (desc->params[i].name, "playback");
      desc->params[i].character  = 'P';
      desc->params[i].type       = JackDriverParamBool;
      desc->params[i].value.i    = TRUE;
      strcpy (desc->params[i].short_desc, "Whether or not to playback");
      strcpy (desc->params[i].long_desc, desc->params[i].short_desc);

      i++;
      strcpy (desc->params[i].name, "duplex");
      desc->params[i].character  = 'D';
      desc->params[i].type       = JackDriverParamBool;
      desc->params[i].value.i    = TRUE;
      strcpy (desc->params[i].short_desc, "Capture and playback");
      strcpy (desc->params[i].long_desc, desc->params[i].short_desc);

      i++;
      strcpy (desc->params[i].name, "rate");
      desc->params[i].character  = 'r';
      desc->params[i].type       = JackDriverParamUInt;
      desc->params[i].value.ui   = 48000U;
      strcpy (desc->params[i].short_desc, "Sample rate");
      strcpy (desc->params[i].long_desc, desc->params[i].short_desc);

      i++;
      strcpy (desc->params[i].name, "period");
      desc->params[i].character  = 'p';
      desc->params[i].type       = JackDriverParamUInt;
      desc->params[i].value.ui   = 1024U;
      strcpy (desc->params[i].short_desc, "Frames per period");
      strcpy (desc->params[i].long_desc, desc->params[i].short_desc);
      
      i++;
      strcpy (desc->params[i].name, "name");
      desc->params[i].character  = 'n';
      desc->params[i].type       = JackDriverParamString;
      desc->params[i].value.ui   = 128U;
      strcpy (desc->params[i].short_desc, "Driver name");
      strcpy (desc->params[i].long_desc, desc->params[i].short_desc);

      i++;
      strcpy (desc->params[i].name, "dither");
      desc->params[i].character  = 'z';
      desc->params[i].type       = JackDriverParamChar;
      desc->params[i].value.c    = '-';
      strcpy (desc->params[i].short_desc, "Dithering mode");
      strcpy (desc->params[i].long_desc,
            "  Dithering Mode:\n"
            "    r : rectangular\n"
            "    t : triangular\n"
            "    s : shaped\n"
            "    - : no dithering");
      
    return desc;
}

const char driver_client_name[] = "portaudio";

jack_driver_t *
driver_initialize (jack_client_t *client, const JSList * params)
{
      jack_nframes_t srate = 48000;
      jack_nframes_t frames_per_interrupt = 1024;
      AudioDeviceID deviceID = 0;
      int capture = FALSE;
      int playback = FALSE;
      int chan_in = -1;
      int chan_out = -1;
      DitherAlgorithm dither = None;
      const JSList * node;
      const jack_driver_param_t * param;
      char *name = NULL;

#ifdef JACK_USE_MACH_THREADS  
      get_device_id_from_num(0,&deviceID); // takes a default value (first device)
#endif
      
      for (node = params; node; node = jack_slist_next (node)) {
            param = (const jack_driver_param_t *) node->data;

            switch (param->character) {
                
            case 'n':
                  name = (char *) param->value.str;
                  PALog("Driver name found %s\n",name);
                  break;
                        
            case 'D':
                  capture = TRUE;
                  playback = TRUE;
                  break;
                                    
            case 'c':
                  chan_in = (int) param->value.ui;
                  chan_out = (int) param->value.ui;
                  break;
                  
            case 'i':
                  chan_in = (int) param->value.ui;
                  break;
            
            case 'o':
                  chan_out = (int) param->value.ui;
                  break;
    
            case 'C':
                  capture = param->value.i;
                  break;
    
            case 'P':
                  playback = param->value.i;
                  break;

            case 'r':
                  srate = param->value.ui;
                  break;
                                    
            case 'p':
                  frames_per_interrupt = (unsigned int) param->value.ui;
                  break;
                  
            case 'z':
                  switch ((int) param->value.c) {
                  case '-':
                        dither = None;
                        break;
    
                  case 'r':
                        dither = Rectangular;
                        break;
    
                  case 's':
                        dither = Shaped;
                        break;
    
                  case 't':
                  default:
                        dither = Triangular;
                        break;
                  }
                  break;
            }
      }

      /* duplex is the default */
      if (!capture && !playback) {
            capture = TRUE;
            playback = TRUE;
      }

      return portaudio_driver_new ("portaudio", client, frames_per_interrupt,
                             srate, capture, playback, chan_in,
                             chan_out, dither, name);
}

void
driver_finish (jack_driver_t *driver)
{
      portaudio_driver_delete ((portaudio_driver_t *) driver);
}


Generated by  Doxygen 1.6.0   Back to index