Browse Source

first import

git-svn-id: svn+ssh://jackaudio.org/trunk/jack@397 0c269be4-1314-0410-8aa9-9f06e86f4224
tags/0.109.0
letz 23 years ago
parent
commit
dcc5c4ea26
2 changed files with 522 additions and 0 deletions
  1. +464
    -0
      drivers/portaudio/portaudio_driver.c
  2. +58
    -0
      drivers/portaudio/portaudio_driver.h

+ 464
- 0
drivers/portaudio/portaudio_driver.c View File

@@ -0,0 +1,464 @@
/*
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
*/

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

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;
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[32];
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, "capture_%lu", 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, "playback_%lu", 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 jack_nframes_t
portaudio_driver_wait (portaudio_driver_t *driver, int extra_fd, int *status, float *delayed_usecs)
{
*status = 0;
*delayed_usecs = 0;
return driver->frames_per_cycle;
}

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)) {
buf = jack_port_get_buffer (port, nframes);
int channels = driver->capture_nchannels;
float* in = driver->inPortAudio;
for (i = 0; i< nframes; i++) buf[i] = in[channels*i+chn];
}
}
driver->engine->control->current_time.usecs = 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;
/* Clear in case of nothing is connected */
memset(driver->outPortAudio, 0, (driver->playback_nchannels * nframes * sizeof(float)));
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)) {
buf = jack_port_get_buffer (port, nframes);
int channels = driver->playback_nchannels;
float* out = driver->outPortAudio;
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;
}

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

/** 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,
DitherAlgorithm dither)
{
portaudio_driver_t *driver;
PaError err;
const PaDeviceInfo *pdi;
int numDevices;
int i,j;
printf ("creating portaudio driver ... %lu|%lu|%lu\n", frames_per_cycle, rate);
driver = (portaudio_driver_t *) calloc (1, sizeof (portaudio_driver_t));

jack_driver_init ((jack_driver_t *) driver);
driver->frame_rate = rate;
driver->frames_per_cycle = frames_per_cycle;

driver->attach = (JackDriverAttachFunction) portaudio_driver_attach;
driver->detach = (JackDriverDetachFunction) portaudio_driver_detach;
driver->wait = (JackDriverWaitFunction) portaudio_driver_wait;
driver->read = (JackDriverReadFunction) portaudio_driver_read;
driver->write = (JackDriverReadFunction) portaudio_driver_write;
driver->null_cycle = (JackDriverNullCycleFunction) portaudio_driver_null_cycle;
driver->start = (JackDriverStartFunction) portaudio_driver_audio_start;
driver->stop = (JackDriverStopFunction) portaudio_driver_audio_stop;
err = Pa_Initialize();
numDevices = Pa_CountDevices();
if( numDevices < 0 )
{
printf("ERROR: Pa_CountDevices returned 0x%x\n", numDevices );
err = numDevices;
goto error;
}
printf("Number of devices = %d\n", numDevices );
for( i=0; i<numDevices; i++ )
{
pdi = Pa_GetDeviceInfo( i );
printf("---------------------------------------------- #%d", i );
if( i == Pa_GetDefaultInputDeviceID() ) {
driver->capture_nchannels = (capturing) ? pdi->maxInputChannels : 0;
}
if( i == Pa_GetDefaultOutputDeviceID() ){
driver->playback_nchannels = (playing) ? pdi->maxOutputChannels : 0;
}
printf("\nName = %s\n", pdi->name);
printf("Max Inputs = %d ", pdi->maxInputChannels);
printf("Max Outputs = %d\n", pdi->maxOutputChannels);
if( pdi->numSampleRates == -1 ){
printf("Sample Rate Range = %f to %f\n", pdi->sampleRates[0], pdi->sampleRates[1] );
}else{
printf("Sample Rates =");
for(j=0; j<pdi->numSampleRates; j++){
printf(" %8.2f,", pdi->sampleRates[j] );
}
printf("\n");
}
printf("Native Sample Formats = ");
if( pdi->nativeSampleFormats & paInt8 ) printf("paInt8, ");
if( pdi->nativeSampleFormats & paUInt8 ) printf("paUInt8, ");
if( pdi->nativeSampleFormats & paInt16 ) printf("paInt16, ");
if( pdi->nativeSampleFormats & paInt32 ) printf("paInt32, ");
if( pdi->nativeSampleFormats & paFloat32 ) printf("paFloat32, ");
if( pdi->nativeSampleFormats & paInt24 ) printf("paInt24, ");
if( pdi->nativeSampleFormats & paPackedInt24 ) printf("paPackedInt24, ");
printf("\n");
}
if(err != paNoError) goto error;
printf("Pa_GetDefaultOutputDeviceID() %ld\n", Pa_GetDefaultOutputDeviceID());
printf("Pa_GetDefaultInputDeviceID() %ld\n", Pa_GetDefaultInputDeviceID());
if (chan > 0) {
driver->capture_nchannels = (driver->capture_nchannels < chan) ? driver->capture_nchannels : chan;
driver->playback_nchannels = (driver->playback_nchannels < chan) ? driver->playback_nchannels : chan;
}
err = Pa_OpenStream(&driver->stream,
((capturing) ? Pa_GetDefaultInputDeviceID() : paNoDevice),
((capturing) ? driver->capture_nchannels : 0),
paFloat32, /* 32 bit floating point input */
NULL,
((playing) ? Pa_GetDefaultOutputDeviceID() : 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;
jack_init_time();
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 */

const char driver_client_name[] = "portaudio";

static void
portaudio_usage ()
{
fprintf (stderr, "\n"
"portaudio PCM driver args:\n"
" -r sample-rate (default: 44.1kHz)\n"
" -c chan (default: harware)\n"
" -p frames-per-period (default: 128)\n"
" -D (duplex, default: yes)\n"
" -C (capture, default: duplex)\n"
" -P (playback, default: duplex)\n"
" -z[r|t|s|-] (dither, rect|tri|shaped|off, default: off)\n"
);
}

jack_driver_t *
driver_initialize (jack_client_t *client, int argc, char **argv)
{
jack_nframes_t srate = 44100;
jack_nframes_t frames_per_interrupt = 128;
int capture = FALSE;
int playback = FALSE;
int chan = -1;
DitherAlgorithm dither = None;
int i;
for (i = 1; i < argc; i++) {
if (argv[i][0] == '-') {
switch (argv[i][1]) {
case 'D':
capture = TRUE;
playback = TRUE;
break;
case 'c':
chan = atoi (argv[i+1]);
i++;
break;
case 'C':
capture = TRUE;
break;
case 'P':
playback = TRUE;
break;
case 'r':
srate = atoi (argv[i+1]);
i++;
break;
case 'p':
frames_per_interrupt = atoi (argv[i+1]);
i++;
break;
case 'z':
switch (argv[i][2]) {
case '-':
dither = None;
break;
case 'r':
dither = Rectangular;
break;
case 's':
dither = Shaped;
break;
case 't':
default:
dither = Triangular;
break;
}
break;
default:
portaudio_usage ();
return NULL;
}
} else {
portaudio_usage ();
return NULL;
}
}

/* duplex is the default */

if (!capture && !playback) {
capture = TRUE;
playback = TRUE;
}

return portaudio_driver_new ("portaudio", client, frames_per_interrupt, srate, capture, playback, chan, dither);
}

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


+ 58
- 0
drivers/portaudio/portaudio_driver.h View File

@@ -0,0 +1,58 @@
/*
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
*/

#ifndef __jack_portaudio_driver_h__
#define __jack_portaudio_driver_h__

#include <jack/types.h>
#include <jack/hardware.h>
#include <jack/driver.h>
#include <jack/memops.h>
#include <jack/jack.h>
#include <jack/internal.h>

#include <PortAudio.h>

typedef struct {

JACK_DRIVER_DECL

struct _jack_engine *engine;
jack_nframes_t frame_rate;
jack_nframes_t frames_per_cycle;
unsigned long user_nperiods;
channel_t playback_nchannels;
channel_t capture_nchannels;
jack_client_t *client;
JSList *capture_ports;
JSList *playback_ports;

float *inPortAudio;
float *outPortAudio;
PortAudioStream* stream;

} portaudio_driver_t;

#endif /* __jack_portaudio_driver_h__ */

Loading…
Cancel
Save