Browse Source

Merged MIDI branch into the trunk.

git-svn-id: svn+ssh://jackaudio.org/trunk/jack@1035 0c269be4-1314-0410-8aa9-9f06e86f4224
tags/0.109.0
dsbaikov 19 years ago
parent
commit
f37b7cc645
17 changed files with 2414 additions and 67 deletions
  1. +2
    -2
      configure.ac
  2. +4
    -0
      drivers/alsa/Makefile.am
  3. +54
    -3
      drivers/alsa/alsa_driver.c
  4. +4
    -0
      drivers/alsa/alsa_driver.h
  5. +38
    -0
      drivers/alsa/alsa_midi.h
  6. +1193
    -0
      drivers/alsa/alsa_rawmidi.c
  7. +870
    -0
      drivers/alsa/alsa_seqmidi.c
  8. +46
    -0
      drivers/alsa/midi_pack.h
  9. +139
    -0
      drivers/alsa/midi_unpack.h
  10. +3
    -0
      example-clients/.cvsignore
  11. +3
    -3
      example-clients/midiseq.c
  12. +4
    -4
      example-clients/midisine.c
  13. +7
    -20
      jack/midiport.h
  14. +1
    -1
      jack/port.h
  15. +14
    -5
      jackd/engine.c
  16. +27
    -25
      libjack/midiport.c
  17. +5
    -4
      libjack/port.c

+ 2
- 2
configure.ac View File

@@ -16,7 +16,7 @@ dnl micro version = incremented when implementation-only
dnl changes are made
dnl ---
JACK_MAJOR_VERSION=0
JACK_MINOR_VERSION=104
JACK_MINOR_VERSION=105
JACK_MICRO_VERSION=0

dnl ---
@@ -44,7 +44,7 @@ dnl slacker than this, and closer to those for the JACK version
dnl number.
dnl ---
JACK_API_CURRENT=0
JACK_API_REVISION=26
JACK_API_REVISION=27
JACK_API_AGE=0

AC_SUBST(JACK_MAJOR_VERSION)


+ 4
- 0
drivers/alsa/Makefile.am View File

@@ -8,9 +8,13 @@ plugin_LTLIBRARIES = jack_alsa.la

jack_alsa_la_LDFLAGS = -module -avoid-version
jack_alsa_la_SOURCES = alsa_driver.c generic_hw.c memops.c \
alsa_seqmidi.c alsa_rawmidi.c \
hammerfall.c hdsp.c ice1712.c usx2y.c

noinst_HEADERS = alsa_driver.h \
alsa_midi.h \
midi_pack.h \
midi_unpack.h \
generic.h \
hammerfall.h \
hdsp.h \


+ 54
- 3
drivers/alsa/alsa_driver.c View File

@@ -1022,6 +1022,9 @@ alsa_driver_start (alsa_driver_t *driver)
malloc (sizeof (struct pollfd) *
(driver->playback_nfds + driver->capture_nfds + 2));

if (driver->midi)
(driver->midi->start)(driver->midi);

if (driver->playback_handle) {
/* fill playback buffer with zeroes, and mark
all fragments as having data.
@@ -1126,6 +1129,9 @@ alsa_driver_stop (alsa_driver_t *driver)
driver->hw->set_input_monitor_mask (driver->hw, 0);
}

if (driver->midi)
(driver->midi->stop)(driver->midi);

return 0;
}

@@ -1553,6 +1559,9 @@ alsa_driver_read (alsa_driver_t *driver, jack_nframes_t nframes)
if (nframes > driver->frames_per_cycle) {
return -1;
}

if (driver->midi)
(driver->midi->read)(driver->midi, nframes);
nread = 0;
contiguous = 0;
@@ -1622,6 +1631,9 @@ alsa_driver_write (alsa_driver_t* driver, jack_nframes_t nframes)
return -1;
}

if (driver->midi)
(driver->midi->write)(driver->midi, nframes);
nwritten = 0;
contiguous = 0;
orig_nframes = nframes;
@@ -1805,6 +1817,12 @@ alsa_driver_attach (alsa_driver_t *driver)
}
}

if (driver->midi) {
int err = (driver->midi->attach)(driver->midi);
if (err)
jack_error("ALSA: cannot attach midi: %d", err);
}

return jack_activate (driver->client);
}
@@ -1818,6 +1836,9 @@ alsa_driver_detach (alsa_driver_t *driver)
return 0;
}

if (driver->midi)
(driver->midi->detach)(driver->midi);
for (node = driver->capture_ports; node;
node = jack_slist_next (node)) {
jack_port_unregister (driver->client,
@@ -1904,6 +1925,9 @@ alsa_driver_delete (alsa_driver_t *driver)
{
JSList *node;

if (driver->midi)
(driver->midi->destroy)(driver->midi);

for (node = driver->clock_sync_listeners; node;
node = jack_slist_next (node)) {
free (node->data);
@@ -1975,7 +1999,8 @@ alsa_driver_new (char *name, char *playback_alsa_device,
int user_playback_nchnls,
int shorts_first,
jack_nframes_t capture_latency,
jack_nframes_t playback_latency
jack_nframes_t playback_latency,
alsa_midi_t *midi_driver
)
{
int err;
@@ -2058,6 +2083,8 @@ alsa_driver_new (char *name, char *playback_alsa_device,
driver->alsa_name_playback = strdup (playback_alsa_device);
driver->alsa_name_capture = strdup (capture_alsa_device);

driver->midi = midi_driver;

if (alsa_driver_check_card_type (driver)) {
alsa_driver_delete (driver);
return NULL;
@@ -2332,7 +2359,7 @@ driver_get_descriptor ()
desc = calloc (1, sizeof (jack_driver_desc_t));

strcpy (desc->name,"alsa");
desc->nparams = 17;
desc->nparams = 18;
params = calloc (desc->nparams, sizeof (jack_driver_param_desc_t));

@@ -2483,6 +2510,18 @@ driver_get_descriptor ()
strcpy (params[i].short_desc, "Extra output latency (frames)");
strcpy (params[i].long_desc, params[i].short_desc);

i++;
strcpy (params[i].name, "midi");
params[i].character = 'X';
params[i].type = JackDriverParamString;
strcpy (params[i].value.str, "none");
strcpy (params[i].short_desc, "ALSA MIDI driver (seq|raw)");
strcpy (params[i].long_desc,
"ALSA MIDI driver:\n"
" none - no MIDI driver\n"
" seq - ALSA Sequencer driver\n"
" raw - ALSA RawMIDI driver\n");

desc->params = params;

return desc;
@@ -2508,6 +2547,8 @@ driver_initialize (jack_client_t *client, const JSList * params)
int shorts_first = FALSE;
jack_nframes_t systemic_input_latency = 0;
jack_nframes_t systemic_output_latency = 0;
char *midi_driver_name = "none";
alsa_midi_t *midi = NULL;
const JSList * node;
const jack_driver_param_t * param;

@@ -2596,6 +2637,10 @@ driver_initialize (jack_client_t *client, const JSList * params)
systemic_output_latency = param->value.ui;
break;

case 'X':
midi_driver_name = strdup (param->value.str);
break;

}
}
@@ -2605,6 +2650,12 @@ driver_initialize (jack_client_t *client, const JSList * params)
playback = TRUE;
}

if (strcmp(midi_driver_name, "seq")==0) {
midi = alsa_seqmidi_new(client, NULL);
} else if (strcmp(midi_driver_name, "raw")==0) {
midi = alsa_rawmidi_new(client);
}

return alsa_driver_new ("alsa_pcm", playback_pcm_name,
capture_pcm_name, client,
frames_per_interrupt,
@@ -2614,7 +2665,7 @@ driver_initialize (jack_client_t *client, const JSList * params)
user_capture_nchnls, user_playback_nchnls,
shorts_first,
systemic_input_latency,
systemic_output_latency);
systemic_output_latency, midi);
}

void


+ 4
- 0
drivers/alsa/alsa_driver.h View File

@@ -39,6 +39,8 @@
#include <jack/memops.h>
#include <jack/jack.h>

#include "./alsa_midi.h"

typedef void (*ReadCopyFunction) (jack_default_audio_sample_t *dst, char *src,
unsigned long src_bytes,
unsigned long src_skip_bytes);
@@ -141,6 +143,8 @@ typedef struct _alsa_driver {
int xrun_count;
int process_count;

alsa_midi_t *midi;

} alsa_driver_t;

static inline void


+ 38
- 0
drivers/alsa/alsa_midi.h View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2006 Dmitry S. Baikov
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#ifndef __jack_alsa_midi_h__
#define __jack_alsa_midi_h__

#include <jack/jack.h>

typedef struct alsa_midi_t alsa_midi_t;
struct alsa_midi_t {
void (*destroy)(alsa_midi_t *amidi);
int (*attach)(alsa_midi_t *amidi);
int (*detach)(alsa_midi_t *amidi);
int (*start)(alsa_midi_t *amidi);
int (*stop)(alsa_midi_t *amidi);
void (*read)(alsa_midi_t *amidi, jack_nframes_t nframes);
void (*write)(alsa_midi_t *amidi, jack_nframes_t nframes);
};

alsa_midi_t* alsa_rawmidi_new(jack_client_t *jack);
alsa_midi_t* alsa_seqmidi_new(jack_client_t *jack, const char* alsa_name);

#endif /* __jack_alsa_midi_h__ */

+ 1193
- 0
drivers/alsa/alsa_rawmidi.c
File diff suppressed because it is too large
View File


+ 870
- 0
drivers/alsa/alsa_seqmidi.c View File

@@ -0,0 +1,870 @@
/*
* ALSA SEQ < - > JACK MIDI bridge
*
* Copyright (c) 2006,2007 Dmitry S. Baikov <c0ff@konstruktiv.org>
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

/*
* alsa_seqmidi_read:
* add new ports
* reads queued snd_seq_event's
* if PORT_EXIT: mark port as dead
* if PORT_ADD, PORT_CHANGE: send addr to port_thread (it also may mark port as dead)
* else process input event
* remove dead ports and send them to port_thread
*
* alsa_seqmidi_write:
* remove dead ports and send them to port_thread
* add new ports
* queue output events
*
* port_thread:
* wait for port_sem
* free deleted ports
* create new ports or mark existing as dead
*/
#include <alsa/asoundlib.h>
#include <jack/jack.h>
#include <jack/midiport.h>
#include <jack/ringbuffer.h>
#include <jack/thread.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <semaphore.h>
#include <time.h>
#include <ctype.h>

#include "./alsa_midi.h"

#ifdef STANDALONE
#define MESSAGE(...) fprintf(stderr, __VA_ARGS__)
#else
#include <jack/messagebuffer.h>
#endif

#define info_log(...) MESSAGE(__VA_ARGS__)
#define error_log(...) MESSAGE(__VA_ARGS__)

#ifdef DEBUG
#define debug_log(...) MESSAGE(__VA_ARGS__)
#else
#define debug_log(...)
#endif

#define NSEC_PER_SEC ((int64_t)1000*1000*1000)

enum {
MAX_PORTS = 64,
MAX_EVENT_SIZE = 1024,
};

typedef struct port_t port_t;

enum {
PORT_HASH_BITS = 4,
PORT_HASH_SIZE = 1 << PORT_HASH_BITS
};

typedef port_t* port_hash_t[PORT_HASH_SIZE];

struct port_t {
port_t *next;
int is_dead;
char name[64];
snd_seq_addr_t remote;
jack_port_t *jack_port;

jack_ringbuffer_t *early_events; // alsa_midi_event_t + data
int64_t last_out_time;

void *jack_buf;
};

typedef struct {
snd_midi_event_t *codec;

jack_ringbuffer_t *new_ports;

port_t *ports[MAX_PORTS];
} stream_t;

typedef struct alsa_seqmidi {
alsa_midi_t ops;
jack_client_t *jack;

snd_seq_t *seq;
int client_id;
int port_id;
int queue;

int keep_walking;

pthread_t port_thread;
sem_t port_sem;
jack_ringbuffer_t *port_add; // snd_seq_addr_t
jack_ringbuffer_t *port_del; // port_t*

stream_t stream[2];

char alsa_name[32];
} alsa_seqmidi_t;

struct alsa_midi_event {
int64_t time;
int size;
};
typedef struct alsa_midi_event alsa_midi_event_t;

struct process_info {
int dir;
jack_nframes_t nframes;
jack_nframes_t period_start;
jack_nframes_t sample_rate;
jack_nframes_t cur_frames;
int64_t alsa_time;
};


enum PortType { PORT_INPUT = 0, PORT_OUTPUT = 1 };

typedef void (*port_jack_func)(alsa_seqmidi_t *self, port_t *port,struct process_info* info);
static void do_jack_input(alsa_seqmidi_t *self, port_t *port, struct process_info* info);
static void do_jack_output(alsa_seqmidi_t *self, port_t *port, struct process_info* info);

typedef struct {
int alsa_mask;
int jack_caps;
char name[4];
port_jack_func jack_func;
} port_type_t;

static port_type_t port_type[2] = {
{
SND_SEQ_PORT_CAP_SUBS_READ,
JackPortIsOutput|JackPortIsPhysical|JackPortIsTerminal,
"in",
do_jack_input
},
{
SND_SEQ_PORT_CAP_SUBS_WRITE,
JackPortIsInput|JackPortIsPhysical|JackPortIsTerminal,
"out",
do_jack_output
}
};


static void alsa_seqmidi_delete(alsa_midi_t *m);
static int alsa_seqmidi_attach(alsa_midi_t *m);
static int alsa_seqmidi_detach(alsa_midi_t *m);
static int alsa_seqmidi_start(alsa_midi_t *m);
static int alsa_seqmidi_stop(alsa_midi_t *m);
static void alsa_seqmidi_read(alsa_midi_t *m, jack_nframes_t nframes);
static void alsa_seqmidi_write(alsa_midi_t *m, jack_nframes_t nframes);

static
void stream_init(alsa_seqmidi_t *self, int dir)
{
stream_t *str = &self->stream[dir];

str->new_ports = jack_ringbuffer_create(MAX_PORTS*sizeof(port_t*));
snd_midi_event_new(MAX_EVENT_SIZE, &str->codec);
}

static void port_free(alsa_seqmidi_t *self, port_t *port);
static void free_ports(alsa_seqmidi_t *self, jack_ringbuffer_t *ports);

static
void stream_attach(alsa_seqmidi_t *self, int dir)
{
}

static
void stream_detach(alsa_seqmidi_t *self, int dir)
{
stream_t *str = &self->stream[dir];
int i;

free_ports(self, str->new_ports);

// delete all ports from hash
for (i=0; i<PORT_HASH_SIZE; ++i) {
port_t *port = str->ports[i];
while (port) {
port_t *next = port->next;
port_free(self, port);
port = next;
}
str->ports[i] = NULL;
}
}

static
void stream_close(alsa_seqmidi_t *self, int dir)
{
stream_t *str = &self->stream[dir];

if (str->codec)
snd_midi_event_free(str->codec);
if (str->new_ports)
jack_ringbuffer_free(str->new_ports);
}

alsa_midi_t* alsa_seqmidi_new(jack_client_t *client, const char* alsa_name)
{
alsa_seqmidi_t *self = calloc(1, sizeof(alsa_seqmidi_t));
debug_log("midi: new\n");
if (!self)
return NULL;
self->jack = client;
if (!alsa_name)
alsa_name = "jack_midi";
snprintf(self->alsa_name, sizeof(self->alsa_name), "%s", alsa_name);

self->port_add = jack_ringbuffer_create(2*MAX_PORTS*sizeof(snd_seq_addr_t));
self->port_del = jack_ringbuffer_create(2*MAX_PORTS*sizeof(port_t*));
sem_init(&self->port_sem, 0, 0);

stream_init(self, PORT_INPUT);
stream_init(self, PORT_OUTPUT);

self->ops.destroy = alsa_seqmidi_delete;
self->ops.attach = alsa_seqmidi_attach;
self->ops.detach = alsa_seqmidi_detach;
self->ops.start = alsa_seqmidi_start;
self->ops.stop = alsa_seqmidi_stop;
self->ops.read = alsa_seqmidi_read;
self->ops.write = alsa_seqmidi_write;
return &self->ops;
}

static
void alsa_seqmidi_delete(alsa_midi_t *m)
{
alsa_seqmidi_t *self = (alsa_seqmidi_t*) m;

debug_log("midi: delete\n");
alsa_seqmidi_detach(m);

stream_close(self, PORT_OUTPUT);
stream_close(self, PORT_INPUT);

jack_ringbuffer_free(self->port_add);
jack_ringbuffer_free(self->port_del);
sem_close(&self->port_sem);

free(self);
}

static
int alsa_seqmidi_attach(alsa_midi_t *m)
{
alsa_seqmidi_t *self = (alsa_seqmidi_t*) m;
int err;

debug_log("midi: attach\n");

if (self->seq)
return -EALREADY;

if ((err = snd_seq_open(&self->seq, "hw", SND_SEQ_OPEN_DUPLEX, 0)) < 0) {
error_log("failed to open alsa seq");
return err;
}
snd_seq_set_client_name(self->seq, self->alsa_name);
self->port_id = snd_seq_create_simple_port(self->seq, "port",
SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_WRITE
#ifndef DEBUG
|SND_SEQ_PORT_CAP_NO_EXPORT
#endif
,SND_SEQ_PORT_TYPE_APPLICATION);
self->client_id = snd_seq_client_id(self->seq);

self->queue = snd_seq_alloc_queue(self->seq);
snd_seq_start_queue(self->seq, self->queue, 0);

stream_attach(self, PORT_INPUT);
stream_attach(self, PORT_OUTPUT);

snd_seq_nonblock(self->seq, 1);

return 0;
}

static
int alsa_seqmidi_detach(alsa_midi_t *m)
{
alsa_seqmidi_t *self = (alsa_seqmidi_t*) m;

debug_log("midi: detach\n");

if (!self->seq)
return -EALREADY;

alsa_seqmidi_stop(m);

jack_ringbuffer_reset(self->port_add);
free_ports(self, self->port_del);

stream_detach(self, PORT_INPUT);
stream_detach(self, PORT_OUTPUT);

snd_seq_close(self->seq);
self->seq = NULL;

return 0;
}

static void* port_thread(void *);

static void add_existing_ports(alsa_seqmidi_t *self);
static void update_ports(alsa_seqmidi_t *self);
static void add_ports(stream_t *str);

static
int alsa_seqmidi_start(alsa_midi_t *m)
{
alsa_seqmidi_t *self = (alsa_seqmidi_t*) m;
int err;

debug_log("midi: start\n");

if (!self->seq)
return -EBADF;

if (self->keep_walking)
return -EALREADY;

snd_seq_connect_from(self->seq, self->port_id, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE);
snd_seq_drop_input(self->seq);

add_existing_ports(self);
update_ports(self);
add_ports(&self->stream[PORT_INPUT]);
add_ports(&self->stream[PORT_OUTPUT]);

self->keep_walking = 1;

if ((err = pthread_create(&self->port_thread, NULL, port_thread, self))) {
self->keep_walking = 0;
return -errno;
}

return 0;
}

static
int alsa_seqmidi_stop(alsa_midi_t *m)
{
alsa_seqmidi_t *self = (alsa_seqmidi_t*) m;

debug_log("midi: stop\n");

if (!self->keep_walking)
return -EALREADY;

snd_seq_disconnect_from(self->seq, self->port_id, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE);

self->keep_walking = 0;

sem_post(&self->port_sem);
pthread_join(self->port_thread, NULL);
self->port_thread = 0;

return 0;
}

static
int alsa_connect_from(alsa_seqmidi_t *self, int client, int port)
{
snd_seq_port_subscribe_t* sub;
snd_seq_addr_t seq_addr;
int err;

snd_seq_port_subscribe_alloca(&sub);
seq_addr.client = client;
seq_addr.port = port;
snd_seq_port_subscribe_set_sender(sub, &seq_addr);
seq_addr.client = self->client_id;
seq_addr.port = self->port_id;
snd_seq_port_subscribe_set_dest(sub, &seq_addr);

snd_seq_port_subscribe_set_time_update(sub, 1);
snd_seq_port_subscribe_set_queue(sub, self->queue);
snd_seq_port_subscribe_set_time_real(sub, 1);

if ((err=snd_seq_subscribe_port(self->seq, sub)))
error_log("can't subscribe to %d:%d - %s\n", client, port, snd_strerror(err));
return err;
}

/*
* ==================== Port routines =============================
*/
static inline
int port_hash(snd_seq_addr_t addr)
{
return (addr.client + addr.port) % PORT_HASH_SIZE;
}

static
port_t* port_get(port_hash_t hash, snd_seq_addr_t addr)
{
port_t **pport = &hash[port_hash(addr)];
while (*pport) {
port_t *port = *pport;
if (port->remote.client == addr.client && port->remote.port == addr.port)
return port;
pport = &port->next;
}
return NULL;
}

static
void port_insert(port_hash_t hash, port_t *port)
{
port_t **pport = &hash[port_hash(port->remote)];
port->next = *pport;
*pport = port;
}

static
void port_setdead(port_hash_t hash, snd_seq_addr_t addr)
{
port_t *port = port_get(hash, addr);
if (port)
port->is_dead = 1; // see jack_process
else
debug_log("port_setdead: not found (%d:%d)\n", addr.client, addr.port);
}

static
void port_free(alsa_seqmidi_t *self, port_t *port)
{
//snd_seq_disconnect_from(self->seq, self->port_id, port->remote.client, port->remote.port);
//snd_seq_disconnect_to(self->seq, self->port_id, port->remote.client, port->remote.port);
if (port->early_events)
jack_ringbuffer_free(port->early_events);
if (port->jack_port)
jack_port_unregister(self->jack, port->jack_port);
info_log("port deleted: %s\n", port->name);

free(port);
}

static
port_t* port_create(alsa_seqmidi_t *self, int type, snd_seq_addr_t addr, const snd_seq_port_info_t *info)
{
port_t *port;
char *c;
int err;

port = calloc(1, sizeof(port_t));
if (!port)
return NULL;

port->remote = addr;

snprintf(port->name, sizeof(port->name), "%s-%d-%d-%s",
port_type[type].name, addr.client, addr.port, snd_seq_port_info_get_name(info));

// replace all offending characters by -
for (c = port->name; *c; ++c)
if (!isalnum(*c))
*c = '-';

port->jack_port = jack_port_register(self->jack,
port->name, JACK_DEFAULT_MIDI_TYPE, port_type[type].jack_caps, 0);
if (!port->jack_port)
goto failed;

if (type == PORT_INPUT)
err = alsa_connect_from(self, port->remote.client, port->remote.port);
else
err = snd_seq_connect_to(self->seq, self->port_id, port->remote.client, port->remote.port);
if (err)
goto failed;

port->early_events = jack_ringbuffer_create(MAX_EVENT_SIZE*16);

info_log("port created: %s\n", port->name);
return port;

failed:
port_free(self, port);
return NULL;
}

/*
* ==================== Port add/del handling thread ==============================
*/
static
void update_port_type(alsa_seqmidi_t *self, int type, snd_seq_addr_t addr, int caps, const snd_seq_port_info_t *info)
{
stream_t *str = &self->stream[type];
int alsa_mask = port_type[type].alsa_mask;
port_t *port = port_get(str->ports, addr);

debug_log("update_port_type(%d:%d)\n", addr.client, addr.port);

if (port && (caps & alsa_mask)!=alsa_mask) {
debug_log("setdead: %s\n", port->name);
port->is_dead = 1;
}

if (!port && (caps & alsa_mask)==alsa_mask) {
assert (jack_ringbuffer_write_space(str->new_ports) >= sizeof(port));
port = port_create(self, type, addr, info);
if (port)
jack_ringbuffer_write(str->new_ports, (char*)&port, sizeof(port));
}
}

static
void update_port(alsa_seqmidi_t *self, snd_seq_addr_t addr, const snd_seq_port_info_t *info)
{
unsigned int port_caps = snd_seq_port_info_get_capability(info);
if (port_caps & SND_SEQ_PORT_CAP_NO_EXPORT)
return;
update_port_type(self, PORT_INPUT, addr, port_caps, info);
update_port_type(self, PORT_OUTPUT, addr, port_caps, info);
}

static
void free_ports(alsa_seqmidi_t *self, jack_ringbuffer_t *ports)
{
port_t *port;
int sz;
while ((sz = jack_ringbuffer_read(ports, (char*)&port, sizeof(port)))) {
assert (sz == sizeof(port));
port_free(self, port);
}
}

static
void update_ports(alsa_seqmidi_t *self)
{
snd_seq_addr_t addr;
int size;

while ((size = jack_ringbuffer_read(self->port_add, (char*)&addr, sizeof(addr)))) {
snd_seq_port_info_t *info;
int err;

snd_seq_port_info_alloca(&info);
assert (size == sizeof(addr));
assert (addr.client != self->client_id);
if ((err=snd_seq_get_any_port_info(self->seq, addr.client, addr.port, info))>=0) {
update_port(self, addr, info);
} else {
//port_setdead(self->stream[PORT_INPUT].ports, addr);
//port_setdead(self->stream[PORT_OUTPUT].ports, addr);
}
}
}

static
void* port_thread(void *arg)
{
alsa_seqmidi_t *self = arg;

while (self->keep_walking) {
sem_wait(&self->port_sem);
free_ports(self, self->port_del);
update_ports(self);
}
debug_log("port_thread exited\n");
return NULL;
}

static
void add_existing_ports(alsa_seqmidi_t *self)
{
snd_seq_addr_t addr;
snd_seq_client_info_t *client_info;
snd_seq_port_info_t *port_info;

snd_seq_client_info_alloca(&client_info);
snd_seq_port_info_alloca(&port_info);
snd_seq_client_info_set_client(client_info, -1);
while (snd_seq_query_next_client(self->seq, client_info) >= 0)
{
addr.client = snd_seq_client_info_get_client(client_info);
if (addr.client == SND_SEQ_CLIENT_SYSTEM || addr.client == self->client_id)
continue;
snd_seq_port_info_set_client(port_info, addr.client);
snd_seq_port_info_set_port(port_info, -1);
while (snd_seq_query_next_port(self->seq, port_info) >= 0)
{
addr.port = snd_seq_port_info_get_port(port_info);
update_port(self, addr, port_info);
}
}
}

/*
* =================== Input/output port handling =========================
*/
static
void set_process_info(struct process_info *info, alsa_seqmidi_t *self, int dir, jack_nframes_t nframes)
{
const snd_seq_real_time_t* alsa_time;
snd_seq_queue_status_t *status;

snd_seq_queue_status_alloca(&status);

info->dir = dir;

info->period_start = jack_last_frame_time(self->jack);
info->nframes = nframes;
info->sample_rate = jack_get_sample_rate(self->jack);

info->cur_frames = jack_frame_time(self->jack);

// immediately get alsa'a real time (uhh, why everybody has their on 'real' time)
snd_seq_get_queue_status(self->seq, self->queue, status);
alsa_time = snd_seq_queue_status_get_real_time(status);
info->alsa_time = alsa_time->tv_sec * NSEC_PER_SEC + alsa_time->tv_nsec;
}

static
void add_ports(stream_t *str)
{
port_t *port;
while (jack_ringbuffer_read(str->new_ports, (char*)&port, sizeof(port))) {
debug_log("jack: inserted port %s\n", port->name);
port_insert(str->ports, port);
}
}

static
void jack_process(alsa_seqmidi_t *self, struct process_info *info)
{
stream_t *str = &self->stream[info->dir];
port_jack_func process = port_type[info->dir].jack_func;
int i, del=0;

add_ports(str);

// process ports
for (i=0; i<PORT_HASH_SIZE; ++i) {
port_t **pport = &str->ports[i];
while (*pport) {
port_t *port = *pport;
port->jack_buf = jack_port_get_buffer(port->jack_port, info->nframes);
if (info->dir == PORT_INPUT)
jack_midi_clear_buffer(port->jack_buf);

if (!port->is_dead)
(*process)(self, port, info);
else if (jack_ringbuffer_write_space(self->port_del) >= sizeof(port)) {
debug_log("jack: removed port %s\n", port->name);
*pport = port->next;
jack_ringbuffer_write(self->port_del, (char*)&port, sizeof(port));
del++;
continue;
}

pport = &port->next;
}
}

if (del)
sem_post(&self->port_sem);
}

/*
* ============================ Input ==============================
*/
static
void do_jack_input(alsa_seqmidi_t *self, port_t *port, struct process_info *info)
{
// process port->early_events
alsa_midi_event_t ev;
while (jack_ringbuffer_read(port->early_events, (char*)&ev, sizeof(ev))) {
jack_midi_data_t* buf;
jack_nframes_t time = ev.time - info->period_start;
if (time < 0)
time = 0;
else if (time >= info->nframes)
time = info->nframes - 1;
buf = jack_midi_event_reserve(port->jack_buf, time, ev.size);
if (buf)
jack_ringbuffer_read(port->early_events, (char*)buf, ev.size);
else
jack_ringbuffer_read_advance(port->early_events, ev.size);
debug_log("input: it's time for %d bytes at %d\n", ev.size, time);
}
}

static
void port_event(alsa_seqmidi_t *self, snd_seq_event_t *ev)
{
const snd_seq_addr_t addr = ev->data.addr;

if (addr.client == self->client_id)
return;

if (ev->type == SND_SEQ_EVENT_PORT_START || ev->type == SND_SEQ_EVENT_PORT_CHANGE) {
assert (jack_ringbuffer_write_space(self->port_add) >= sizeof(addr));

debug_log("port_event: add/change %d:%d\n", addr.client, addr.port);
jack_ringbuffer_write(self->port_add, (char*)&addr, sizeof(addr));
sem_post(&self->port_sem);
} else if (ev->type == SND_SEQ_EVENT_PORT_EXIT) {
debug_log("port_event: del %d:%d\n", addr.client, addr.port);
port_setdead(self->stream[PORT_INPUT].ports, addr);
port_setdead(self->stream[PORT_OUTPUT].ports, addr);
}
}

static
void input_event(alsa_seqmidi_t *self, snd_seq_event_t *alsa_event, struct process_info* info)
{
jack_midi_data_t data[MAX_EVENT_SIZE];
stream_t *str = &self->stream[PORT_INPUT];
long size;
int64_t alsa_time, time_offset;
int64_t frame_offset, event_frame;
port_t *port;

port = port_get(str->ports, alsa_event->source);
if (!port)
return;

/*
* RPNs, NRPNs, Bank Change, etc. need special handling
* but seems, ALSA does it for us already.
*/
snd_midi_event_reset_decode(str->codec);
if ((size = snd_midi_event_decode(str->codec, data, sizeof(data), alsa_event))<0)
return;

// fixup NoteOn with vel 0
if (data[0] == 0x90 && data[2] == 0x00) {
data[0] = 0x80;
data[2] = 0x40;
}

alsa_time = alsa_event->time.time.tv_sec * NSEC_PER_SEC + alsa_event->time.time.tv_nsec;
time_offset = info->alsa_time - alsa_time;
frame_offset = (info->sample_rate * time_offset) / NSEC_PER_SEC;
event_frame = (int64_t)info->cur_frames - info->period_start - frame_offset + info->nframes;

debug_log("input: %d bytes at event_frame=%d\n", (int)size, (int)event_frame);

if (event_frame >= info->nframes &&
jack_ringbuffer_write_space(port->early_events) >= (sizeof(alsa_midi_event_t) + size)) {
alsa_midi_event_t ev;
ev.time = event_frame + info->period_start;
ev.size = size;
jack_ringbuffer_write(port->early_events, (char*)&ev, sizeof(ev));
jack_ringbuffer_write(port->early_events, (char*)data, size);
debug_log("postponed to next frame +%d\n", (int) (event_frame - info->nframes));
return;
}

if (event_frame < 0)
event_frame = 0;
else if (event_frame >= info->nframes)
event_frame = info->nframes - 1;

jack_midi_event_write(port->jack_buf, event_frame, data, size);
}

static
void alsa_seqmidi_read(alsa_midi_t *m, jack_nframes_t nframes)
{
alsa_seqmidi_t *self = (alsa_seqmidi_t*) m;
int res;
snd_seq_event_t *event;
struct process_info info;

if (!self->keep_walking)
return;

set_process_info(&info, self, PORT_INPUT, nframes);
jack_process(self, &info);

while ((res = snd_seq_event_input(self->seq, &event))>0) {
if (event->source.client == SND_SEQ_CLIENT_SYSTEM)
port_event(self, event);
else
input_event(self, event, &info);
}
}

/*
* ============================ Output ==============================
*/

static
void do_jack_output(alsa_seqmidi_t *self, port_t *port, struct process_info* info)
{
stream_t *str = &self->stream[info->dir];
int nevents = jack_midi_get_event_count(port->jack_buf);
int i;
for (i=0; i<nevents; ++i) {
jack_midi_event_t jack_event;
snd_seq_event_t alsa_event;
jack_nframes_t frame_offset;
int64_t out_time;
snd_seq_real_time_t out_rt;
int err;

jack_midi_event_get(&jack_event, port->jack_buf, i);

snd_seq_ev_clear(&alsa_event);
snd_midi_event_reset_encode(str->codec);
if (!snd_midi_event_encode(str->codec, jack_event.buffer, jack_event.size, &alsa_event))
continue; // invalid event

snd_seq_ev_set_source(&alsa_event, self->port_id);
snd_seq_ev_set_dest(&alsa_event, port->remote.client, port->remote.port);

frame_offset = jack_event.time + info->period_start + info->nframes - info->cur_frames;
out_time = info->alsa_time + (frame_offset * NSEC_PER_SEC) / info->sample_rate;

// we should use absolute time to prevent reordering caused by rounding errors
if (out_time < port->last_out_time)
out_time = port->last_out_time;
else
port->last_out_time = out_time;

out_rt.tv_nsec = out_time % NSEC_PER_SEC;
out_rt.tv_sec = out_time / NSEC_PER_SEC;
snd_seq_ev_schedule_real(&alsa_event, self->queue, 0, &out_rt);

err = snd_seq_event_output(self->seq, &alsa_event);
debug_log("alsa_out: written %d bytes to %s at +%d: %d\n", jack_event.size, port->name, (int)frame_offset, err);
}
}

static
void alsa_seqmidi_write(alsa_midi_t *m, jack_nframes_t nframes)
{
alsa_seqmidi_t *self = (alsa_seqmidi_t*) m;
struct process_info info;

if (!self->keep_walking)
return;

set_process_info(&info, self, PORT_OUTPUT, nframes);
jack_process(self, &info);
snd_seq_drain_output(self->seq);
}

+ 46
- 0
drivers/alsa/midi_pack.h View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 2006,2007 Dmitry S. Baikov
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#ifndef __jack_midi_pack_h__
#define __jack_midi_pack_h__

typedef struct {
int running_status;
} midi_pack_t;

static inline
void midi_pack_reset(midi_pack_t *p)
{
p->running_status = 0;
}

static
void midi_pack_event(midi_pack_t *p, jack_midi_event_t *e)
{
if (e->buffer[0] >= 0x80 && e->buffer[0] < 0xF0) { // Voice Message
if (e->buffer[0] == p->running_status) {
e->buffer++;
e->size--;
} else
p->running_status = e->buffer[0];
} else if (e->buffer[0] < 0xF8) { // not System Realtime
p->running_status = 0;
}
}

#endif /* __jack_midi_pack_h__ */

+ 139
- 0
drivers/alsa/midi_unpack.h View File

@@ -0,0 +1,139 @@
/*
* Copyright (c) 2006,2007 Dmitry S. Baikov
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#ifndef __jack_midi_unpack_h__
#define __jack_midi_unpack_h__

enum {
MIDI_UNPACK_MAX_MSG = 1024
};

typedef struct {
int pos, need, size;
unsigned char data[MIDI_UNPACK_MAX_MSG];
} midi_unpack_t;

static inline
void midi_unpack_init(midi_unpack_t *u)
{
u->pos = 0;
u->size = sizeof(u->data);
u->need = u->size;
}

static inline
void midi_unpack_reset(midi_unpack_t *u)
{
u->pos = 0;
u->need = u->size;
}

static const unsigned char midi_voice_len[] = {
3, /*0x80 Note Off*/
3, /*0x90 Note On*/
3, /*0xA0 Aftertouch*/
3, /*0xB0 Control Change*/
2, /*0xC0 Program Change*/
2, /*0xD0 Channel Pressure*/
3, /*0xE0 Pitch Wheel*/
1 /*0xF0 System*/
};

static const unsigned char midi_system_len[] = {
0, /*0xF0 System Exclusive Start*/
2, /*0xF1 MTC Quarter Frame*/
3, /*0xF2 Song Postion*/
2, /*0xF3 Song Select*/
0, /*0xF4 undefined*/
0, /*0xF5 undefined*/
1, /*0xF6 Tune Request*/
1 /*0xF7 System Exlusive End*/
};

static
int midi_unpack_buf(midi_unpack_t *buf, const unsigned char *data, int len, void *jack_port_buf, jack_nframes_t time)
{
int i;
for (i=0; i<len; ++i)
{
const unsigned char byte = data[i];
if (byte >= 0xF8) // system realtime
{
jack_midi_event_write(jack_port_buf, time, &data[i], 1);
//printf("midi_unpack: written system relatime event\n");
//midi_input_write(in, &data[i], 1);
}
else if (byte < 0x80) // data
{
assert (buf->pos < buf->size);
buf->data[buf->pos++] = byte;
}
else if (byte < 0xF0) // voice
{
assert (byte >= 0x80 && byte < 0xF0);
//buf->need = ((byte|0x0F) == 0xCF || (byte|0x0F)==0xDF) ? 2 : 3;
buf->need = midi_voice_len[(byte-0x80)>>4];
buf->data[0] = byte;
buf->pos = 1;
}
else if (byte == 0xF7) // sysex end
{
assert (buf->pos < buf->size);
buf->data[buf->pos++] = byte;
buf->need = buf->pos;
}
else
{
assert (byte >= 0xF0 && byte < 0xF8);
buf->pos = 1;
buf->data[0] = byte;
buf->need = midi_system_len[byte - 0xF0];
if (!buf->need)
buf->need = buf->size;
}
if (buf->pos == buf->need)
{
// TODO: deal with big sysex'es (they are silently dropped for now)
if (buf->data[0] >= 0x80 || (buf->data[0]==0xF0 && buf->data[buf->pos-1] == 0xF7)) {
/* convert Note On with velocity 0 to Note Off */
if ((buf->data[0] & 0xF0) == 0x90 && buf->data[2] == 0) {
// we use temp array here to keep running status in sync
jack_midi_data_t temp[3] = { 0x80, 0, 0x40 };
temp[0] |= buf->data[0] & 0x0F;
temp[1] = buf->data[1];
jack_midi_event_write(jack_port_buf, time, temp, 3);
} else
jack_midi_event_write(jack_port_buf, time, &buf->data[0], buf->pos);
//printf("midi_unpack: written %d-byte event\n", buf->pos);
//midi_input_write(in, &buf->data[0], buf->pos);
}
/* keep running status */
if (buf->data[0] >= 0x80 && buf->data[0] < 0xF0)
buf->pos = 1;
else
{
buf->pos = 0;
buf->need = buf->size;
}
}
}
assert (i==len);
return i;
}

#endif /* __jack_midi_unpack_h__ */

+ 3
- 0
example-clients/.cvsignore View File

@@ -21,3 +21,6 @@ inprocess.la
inprocess.lo
intime.la
intime.lo
jack_alias
jack_evmon
jack_thread_wait

+ 3
- 3
example-clients/midiseq.c View File

@@ -45,7 +45,7 @@ int process(jack_nframes_t nframes, void *arg)
int i,j;
void* port_buf = jack_port_get_buffer(output_port, nframes);
unsigned char* buffer;
jack_midi_clear_buffer(port_buf, nframes);
jack_midi_clear_buffer(port_buf);
/*memset(buffer, 0, nframes*sizeof(jack_default_audio_sample_t));*/

for(i=0; i<nframes; i++)
@@ -54,7 +54,7 @@ int process(jack_nframes_t nframes, void *arg)
{
if(note_starts[j] == loop_index)
{
buffer = jack_midi_event_reserve(port_buf, i, 3, nframes);
buffer = jack_midi_event_reserve(port_buf, i, 3);
/* printf("wrote a note on, port buffer = 0x%x, event buffer = 0x%x\n", port_buf, buffer);*/
buffer[2] = 64; /* velocity */
buffer[1] = note_frqs[j];
@@ -62,7 +62,7 @@ int process(jack_nframes_t nframes, void *arg)
}
else if(note_starts[j] + note_lengths[j] == loop_index)
{
buffer = jack_midi_event_reserve(port_buf, i, 3, nframes);
buffer = jack_midi_event_reserve(port_buf, i, 3);
/* printf("wrote a note off, port buffer = 0x%x, event buffer = 0x%x\n", port_buf, buffer);*/
buffer[2] = 64; /* velocity */
buffer[1] = note_frqs[j];


+ 4
- 4
example-clients/midisine.c View File

@@ -49,18 +49,18 @@ int process(jack_nframes_t nframes, void *arg)
jack_default_audio_sample_t *out = (jack_default_audio_sample_t *) jack_port_get_buffer (output_port, nframes);
jack_midi_event_t in_event;
jack_nframes_t event_index = 0;
jack_nframes_t event_count = jack_midi_get_event_count(port_buf, nframes);
jack_nframes_t event_count = jack_midi_get_event_count(port_buf);
if(event_count > 1)
{
printf(" midisine: have %d events\n", event_count);
for(i=0; i<event_count; i++)
{
jack_midi_event_get(&in_event, port_buf, i, nframes);
jack_midi_event_get(&in_event, port_buf, i);
printf(" event %d time is %d. 1st byte is 0x%x\n", i, in_event.time, *(in_event.buffer));
}
/* printf("1st byte of 1st event addr is %p\n", in_events[0].buffer);*/
}
jack_midi_event_get(&in_event, port_buf, 0, nframes);
jack_midi_event_get(&in_event, port_buf, 0);
for(i=0; i<nframes; i++)
{
if((in_event.time == i) && (event_index < event_count))
@@ -79,7 +79,7 @@ int process(jack_nframes_t nframes, void *arg)
}
event_index++;
if(event_index < event_count)
jack_midi_event_get(&in_event, port_buf, event_index, nframes);
jack_midi_event_get(&in_event, port_buf, event_index);
}
ramp += note_frqs[note];
ramp = (ramp > 1.0) ? ramp - 2.0 : ramp;


+ 7
- 20
jack/midiport.h View File

@@ -45,12 +45,10 @@ typedef struct _jack_midi_event
/* Get number of events in a port buffer.
*
* @param port_buffer Port buffer from which to retrieve event.
* @param nframes Number of valid frames this cycle.
* @return number of events inside @a port_buffer
*/
jack_nframes_t
jack_midi_get_event_count(void* port_buffer,
jack_nframes_t nframes);
jack_midi_get_event_count(void* port_buffer);


/** Get a MIDI event from an event port buffer.
@@ -62,14 +60,12 @@ jack_midi_get_event_count(void* port_buffer,
* @param event Event structure to store retrieved event in.
* @param port_buffer Port buffer from which to retrieve event.
* @param event_index Index of event to retrieve.
* @param nframes Number of valid frames this cycle.
* @return 0 on success, ENODATA if buffer is empty.
*/
int
jack_midi_event_get(jack_midi_event_t *event,
void *port_buffer,
jack_nframes_t event_index,
jack_nframes_t nframes);
jack_nframes_t event_index);


/** Clear an event buffer.
@@ -79,11 +75,9 @@ jack_midi_event_get(jack_midi_event_t *event,
* function may not be called on an input port's buffer.
*
* @param port_buffer Port buffer to clear (must be an output port buffer).
* @param nframes Number of valid frames this cycle.
*/
void
jack_midi_clear_buffer(void *port_buffer,
jack_nframes_t nframes);
jack_midi_clear_buffer(void *port_buffer);


/** Get the size of the largest event that can be stored by the port.
@@ -92,10 +86,9 @@ jack_midi_clear_buffer(void *port_buffer,
* events already stored in the port.
*
* @param port_buffer Port buffer to check size of.
* @param nframes Number of valid frames this cycle.
*/
size_t
jack_midi_max_event_size(void* port_buffer, jack_nframes_t nframes);
jack_midi_max_event_size(void* port_buffer);


/** Allocate space for an event to be written to an event port buffer.
@@ -110,15 +103,13 @@ jack_midi_max_event_size(void* port_buffer, jack_nframes_t nframes);
* @param port_buffer Buffer to write event to.
* @param time Sample offset of event.
* @param data_size Length of event's raw data in bytes.
* @param nframes Number of valid frames this event.
* @return Pointer to the beginning of the reserved event's data buffer, or
* NULL on error (ie not enough space).
*/
jack_midi_data_t*
jack_midi_event_reserve(void *port_buffer,
jack_nframes_t time,
size_t data_size,
jack_nframes_t nframes);
size_t data_size);


/** Write an event into an event port buffer.
@@ -131,15 +122,13 @@ jack_midi_event_reserve(void *port_buffer,
* @param time Sample offset of event.
* @param data Message data to be written.
* @param data_size Length of @a data in bytes.
* @param nframes Number of valid frames this event.
* @return 0 on success, ENOBUFS if there's not enough space in buffer for event.
*/
int
jack_midi_event_write(void *port_buffer,
jack_nframes_t time,
const jack_midi_data_t *data,
size_t data_size,
jack_nframes_t nframes);
size_t data_size);


/** Get the number of events that could not be written to @a port_buffer.
@@ -148,12 +137,10 @@ jack_midi_event_write(void *port_buffer,
* Currently the only way this can happen is if events are lost on port mixdown.
*
* @param port_buffer Port to receive count for.
* @param nframes Number of valid frames this cycle.
* @returns Number of events that could not be written to @a port_buffer.
*/
jack_nframes_t
jack_midi_get_lost_event_count(void *port_buffer,
jack_nframes_t nframes);
jack_midi_get_lost_event_count(void *port_buffer);


#ifdef __cplusplus


+ 1
- 1
jack/port.h View File

@@ -120,7 +120,7 @@ typedef struct _jack_port_functions {
* A better solution is to make jack_engine_place_buffers to be type-specific,
* but this works.
*/
void (*buffer_init)(void *buffer, size_t size);
void (*buffer_init)(void *buffer, size_t size, jack_nframes_t);

/* Function to mixdown multiple inputs to a buffer. Can be NULL,
* indicating that multiple input connections are not legal for


+ 14
- 5
jackd/engine.c View File

@@ -332,7 +332,8 @@ jack_engine_place_port_buffers (jack_engine_t* engine,
jack_port_type_id_t ptid,
jack_shmsize_t one_buffer,
jack_shmsize_t size,
unsigned long nports)
unsigned long nports,
jack_nframes_t nframes)
{
jack_shmsize_t offset; /* shared memory offset */
jack_port_buffer_info_t *bi;
@@ -408,7 +409,7 @@ jack_engine_place_port_buffers (jack_engine_t* engine,

bi = pti->info;
for (i=0; i<nports; ++i, ++bi)
pfuncs->buffer_init(shm_segment + bi->offset, one_buffer);
pfuncs->buffer_init(shm_segment + bi->offset, one_buffer, nframes);
}

pthread_mutex_unlock (&pti->lock);
@@ -466,7 +467,7 @@ jack_resize_port_segment (jack_engine_t *engine,
}
}

jack_engine_place_port_buffers (engine, ptid, one_buffer, size, nports);
jack_engine_place_port_buffers (engine, ptid, one_buffer, size, nports, engine->control->buffer_size);

#ifdef USE_MLOCK
if (engine->control->real_time) {
@@ -3475,12 +3476,19 @@ jack_port_do_register (jack_engine_t *engine, jack_request_t *req)
req->x.port_info.client_id))
== NULL) {
jack_error ("unknown client id in port registration request");
jack_unlock_graph (engine);
return -1;
}

if ((port = jack_get_port_by_name(engine, req->x.port_info.name)) != NULL) {
jack_error ("duplicate port name in port registration request");
jack_unlock_graph (engine);
return -1;
}
jack_unlock_graph (engine);

if ((port_id = jack_get_free_port (engine)) == (jack_port_id_t) -1) {
jack_error ("no ports available!");
jack_unlock_graph (engine);
return -1;
}

@@ -3501,10 +3509,11 @@ jack_port_do_register (jack_engine_t *engine, jack_request_t *req)
if (jack_port_assign_buffer (engine, port)) {
jack_error ("cannot assign buffer for port");
jack_port_release (engine, &engine->internal_ports[port_id]);
jack_unlock_graph (engine);
return -1;
}

jack_lock_graph (engine);
client->ports = jack_slist_prepend (client->ports, port);
jack_port_registration_notify (engine, port_id, TRUE);
jack_unlock_graph (engine);


+ 27
- 25
libjack/midiport.c View File

@@ -28,6 +28,7 @@


typedef struct _jack_midi_port_info_private {
jack_nframes_t nframes; /**< Number of frames in buffer */
size_t buffer_size; /**< Size of buffer in bytes */
jack_nframes_t event_count; /**< Number of events stored in this buffer */
jack_nframes_t last_write_loc; /**< Used for both writing and mixdown */
@@ -44,11 +45,13 @@ typedef struct _jack_midi_port_internal_event {
/* jack_midi_port_functions.buffer_init */
static void
jack_midi_buffer_init(void *port_buffer,
size_t buffer_size)
size_t buffer_size,
jack_nframes_t nframes)
{
jack_midi_port_info_private_t *info =
(jack_midi_port_info_private_t *) port_buffer;
/* We can also add some magic field to midi buffer to validate client calls */
info->nframes = nframes;
info->buffer_size = buffer_size;
info->event_count = 0;
info->last_write_loc = 0;
@@ -57,8 +60,7 @@ jack_midi_buffer_init(void *port_buffer,


jack_nframes_t
jack_midi_get_event_count(void *port_buffer,
jack_nframes_t nframes)
jack_midi_get_event_count(void *port_buffer)
{
jack_midi_port_info_private_t *info =
(jack_midi_port_info_private_t *) port_buffer;
@@ -69,8 +71,7 @@ jack_midi_get_event_count(void *port_buffer,
int
jack_midi_event_get(jack_midi_event_t *event,
void *port_buffer,
jack_nframes_t event_idx,
jack_nframes_t nframes)
jack_nframes_t event_idx)
{
jack_midi_port_internal_event_t *port_event;
jack_midi_port_info_private_t *info =
@@ -91,8 +92,7 @@ jack_midi_event_get(jack_midi_event_t *event,


size_t
jack_midi_max_event_size(void *port_buffer,
jack_nframes_t nframes)
jack_midi_max_event_size(void *port_buffer)
{
jack_midi_port_info_private_t *info =
(jack_midi_port_info_private_t *) port_buffer;
@@ -116,8 +116,7 @@ jack_midi_max_event_size(void *port_buffer,
jack_midi_data_t*
jack_midi_event_reserve(void *port_buffer,
jack_nframes_t time,
size_t data_size,
jack_nframes_t nframes)
size_t data_size)
{
jack_midi_data_t *retbuf = (jack_midi_data_t *) port_buffer;

@@ -128,11 +127,11 @@ jack_midi_event_reserve(void *port_buffer,
size_t buffer_size =
info->buffer_size;
if (time < 0 || time >= nframes)
return NULL;
if (time < 0 || time >= info->nframes)
goto failed;
if (info->event_count > 0 && time < event_buffer[info->event_count-1].time)
return NULL;
goto failed;

/* Check if data_size is >0 and there is enough space in the buffer for the event. */
if (data_size <=0 ||
@@ -140,7 +139,7 @@ jack_midi_event_reserve(void *port_buffer,
+ ((info->event_count + 1)
* sizeof(jack_midi_port_internal_event_t))
+ data_size > buffer_size) {
return NULL;
goto failed;
} else {
info->last_write_loc += data_size;
retbuf = &retbuf[buffer_size - 1 - info->last_write_loc];
@@ -151,6 +150,9 @@ jack_midi_event_reserve(void *port_buffer,
info->event_count += 1;
return retbuf;
}
failed:
info->events_lost++;
return NULL;
}


@@ -158,11 +160,10 @@ int
jack_midi_event_write(void *port_buffer,
jack_nframes_t time,
const jack_midi_data_t *data,
size_t data_size,
jack_nframes_t nframes)
size_t data_size)
{
jack_midi_data_t *retbuf =
jack_midi_event_reserve(port_buffer, time, data_size, nframes);
jack_midi_event_reserve(port_buffer, time, data_size);

if (retbuf) {
memcpy(retbuf, data, data_size);
@@ -179,8 +180,7 @@ jack_midi_event_write(void *port_buffer,
* been reset.
*/
void
jack_midi_clear_buffer(void *port_buffer,
jack_nframes_t nframes)
jack_midi_clear_buffer(void *port_buffer)
{
jack_midi_port_info_private_t *info =
(jack_midi_port_info_private_t *) port_buffer;
@@ -193,14 +193,14 @@ jack_midi_clear_buffer(void *port_buffer,

/* jack_midi_port_functions.mixdown */
static void
jack_midi_port_mixdown(jack_port_t *port,
jack_nframes_t nframes)
jack_midi_port_mixdown(jack_port_t *port, jack_nframes_t nframes)
{
JSList *node;
jack_port_t *input;
jack_nframes_t num_events = 0;
jack_nframes_t i = 0;
int err = 0;
jack_nframes_t lost_events = 0;

/* The next (single) event to mix in to the buffer */
jack_midi_port_info_private_t *earliest_info;
@@ -211,7 +211,7 @@ jack_midi_port_mixdown(jack_port_t *port,
jack_midi_port_internal_event_t *in_events; /* Corresponds to in_info */
jack_midi_port_info_private_t *out_info; /* Output 'buffer' */

jack_midi_clear_buffer(port->mix_buffer, nframes);
jack_midi_clear_buffer(port->mix_buffer);
out_info = (jack_midi_port_info_private_t *) port->mix_buffer;

@@ -228,6 +228,7 @@ jack_midi_port_mixdown(jack_port_t *port,
in_info =
(jack_midi_port_info_private_t *) jack_output_port_buffer(input);
num_events += in_info->event_count;
lost_events += in_info->events_lost;
in_info->last_write_loc = 0;
}

@@ -267,8 +268,7 @@ jack_midi_port_mixdown(jack_port_t *port,
jack_port_buffer(port),
earliest_event->time,
&earliest_buffer[earliest_event->byte_offset],
earliest_event->size,
nframes);
earliest_event->size);
earliest_info->last_write_loc++;

@@ -279,12 +279,14 @@ jack_midi_port_mixdown(jack_port_t *port,
}
}
assert(out_info->event_count == num_events - out_info->events_lost);

// inherit total lost events count from all connected ports.
out_info->events_lost += lost_events;
}


jack_nframes_t
jack_midi_get_lost_event_count(void *port_buffer,
jack_nframes_t nframes)
jack_midi_get_lost_event_count(void *port_buffer)
{
return ((jack_midi_port_info_private_t *) port_buffer)->events_lost;
}


+ 5
- 4
libjack/port.c View File

@@ -37,7 +37,8 @@
#include "local.h"

static void jack_generic_buffer_init(void *port_buffer,
size_t buffer_size);
size_t buffer_size,
jack_nframes_t nframes);

static void jack_audio_port_mixdown (jack_port_t *port,
jack_nframes_t nframes);
@@ -359,8 +360,8 @@ jack_get_port_functions(jack_port_type_id_t ptid)
* Fills buffer with zeroes. For audio ports, engine->silent_buffer relies on it.
*/
static void
jack_generic_buffer_init(void *buffer, size_t size)
{
jack_generic_buffer_init(void *buffer, size_t size, jack_nframes_t nframes)
{
memset(buffer, 0, size);
}

@@ -749,7 +750,7 @@ jack_port_get_buffer (jack_port_t *port, jack_nframes_t nframes)
* sizeof (jack_default_audio_sample_t)
* nframes;
port->mix_buffer = jack_pool_alloc (buffer_size);
port->fptr.buffer_init (port->mix_buffer, buffer_size);
port->fptr.buffer_init (port->mix_buffer, buffer_size, nframes);
}
port->fptr.mixdown (port, nframes);
return (void *) port->mix_buffer;


Loading…
Cancel
Save