@@ -25,8 +25,9 @@ | |||||
#include "alsathread.h" | #include "alsathread.h" | ||||
Jackclient::Jackclient (jack_client_t* cl, const char*jserv, int mode, int nchan) : | |||||
Jackclient::Jackclient (jack_client_t* cl, const char*jserv, int mode, int nchan, void *arg) : | |||||
_client (cl), | _client (cl), | ||||
_arg (arg), | |||||
_mode (mode), | _mode (mode), | ||||
_nchan (nchan), | _nchan (nchan), | ||||
_state (INIT), | _state (INIT), | ||||
@@ -31,7 +31,7 @@ class Jackclient | |||||
{ | { | ||||
public: | public: | ||||
Jackclient (jack_client_t*, const char *jserv, int mode, int nchan); | |||||
Jackclient (jack_client_t*, const char *jserv, int mode, int nchan, void *arg); | |||||
virtual ~Jackclient (void); | virtual ~Jackclient (void); | ||||
enum { PLAY, CAPT }; | enum { PLAY, CAPT }; | ||||
@@ -51,6 +51,7 @@ public: | |||||
int bsize (void) const { return _bsize; } | int bsize (void) const { return _bsize; } | ||||
int rprio (void) const { return _rprio; } | int rprio (void) const { return _rprio; } | ||||
void register_ports (int nports); | void register_ports (int nports); | ||||
void *getarg(void) const { return _arg; } | |||||
private: | private: | ||||
@@ -80,6 +81,7 @@ private: | |||||
jack_client_t *_client; | jack_client_t *_client; | ||||
jack_port_t *_ports [256]; | jack_port_t *_ports [256]; | ||||
void *_arg; | |||||
const char *_jname; | const char *_jname; | ||||
int _mode; | int _mode; | ||||
int _nchan; | int _nchan; | ||||
@@ -27,25 +27,7 @@ | |||||
#include "jackclient.h" | #include "jackclient.h" | ||||
#include "lfqueue.h" | #include "lfqueue.h" | ||||
static Lfq_int32 commq (16); | |||||
static Lfq_adata alsaq (256); | |||||
static Lfq_jdata infoq (256); | |||||
static Lfq_audio *audioq = 0; | |||||
static bool stop = false; | |||||
static const char *clopt = "hvLj:d:r:p:n:c:Q:I:"; | |||||
static bool v_opt = false; | |||||
static bool L_opt = false; | |||||
static const char *jname = APPNAME; | |||||
static const char *device = 0; | |||||
static int fsamp = 0; // try to get from server if unspecified | |||||
static int bsize = 0; // try to get from server if unspecified | |||||
static int nfrag = 2; | |||||
static int nchan = 2; | |||||
static int rqual = 48; | |||||
static int ltcor = 0; | |||||
static const char *clopt = "hvLj:d:r:p:n:c:Q:I:"; | |||||
static void help (void) | static void help (void) | ||||
{ | { | ||||
@@ -68,57 +50,101 @@ static void help (void) | |||||
exit (1); | exit (1); | ||||
} | } | ||||
static int procoptions (int ac, const char *av []) | |||||
class zita_a2j | |||||
{ | { | ||||
int k; | |||||
optind = 1; | |||||
opterr = 0; | |||||
while ((k = getopt (ac, (char **) av, (char *) clopt)) != -1) | |||||
Lfq_int32 *commq; | |||||
Lfq_adata *alsaq; | |||||
Lfq_jdata *infoq; | |||||
Lfq_audio *audioq; | |||||
bool stop; | |||||
bool v_opt; | |||||
bool L_opt; | |||||
char *jname; | |||||
char *device; | |||||
int fsamp; | |||||
int bsize; | |||||
int nfrag; | |||||
int nchan; | |||||
int rqual; | |||||
int ltcor; | |||||
public: | |||||
zita_a2j() | |||||
{ | |||||
commq = new Lfq_int32(16); | |||||
alsaq = new Lfq_adata(256); | |||||
infoq = new Lfq_jdata(256); | |||||
audioq = 0; | |||||
stop = false; | |||||
v_opt = false; | |||||
L_opt = false; | |||||
jname = strdup(APPNAME); | |||||
device = 0; | |||||
fsamp = 0; | |||||
bsize = 0; | |||||
nfrag = 2; | |||||
nchan = 2; | |||||
rqual = 48; | |||||
ltcor = 0; | |||||
A = 0; | |||||
C = 0; | |||||
J = 0; | |||||
} | |||||
private: | |||||
int procoptions (int ac, const char *av []) | |||||
{ | { | ||||
if (optarg && (*optarg == '-')) | |||||
int k; | |||||
optind = 1; | |||||
opterr = 0; | |||||
while ((k = getopt (ac, (char **) av, (char *) clopt)) != -1) | |||||
{ | { | ||||
fprintf (stderr, " Missing argument for '-%c' option.\n", k); | |||||
fprintf (stderr, " Use '-h' to see all options.\n"); | |||||
exit (1); | |||||
if (optarg && (*optarg == '-')) | |||||
{ | |||||
fprintf (stderr, " Missing argument for '-%c' option.\n", k); | |||||
fprintf (stderr, " Use '-h' to see all options.\n"); | |||||
exit (1); | |||||
} | |||||
switch (k) | |||||
{ | |||||
case 'h' : help (); exit (0); | |||||
case 'v' : v_opt = true; break; | |||||
case 'L' : L_opt = true; break; | |||||
case 'j' : jname = optarg; break; | |||||
case 'd' : device = optarg; break; | |||||
case 'r' : fsamp = atoi (optarg); break; | |||||
case 'p' : bsize = atoi (optarg); break; | |||||
case 'n' : nfrag = atoi (optarg); break; | |||||
case 'c' : nchan = atoi (optarg); break; | |||||
case 'Q' : rqual = atoi (optarg); break; | |||||
case 'I' : ltcor = atoi (optarg); break; | |||||
case '?': | |||||
if (optopt != ':' && strchr (clopt, optopt)) | |||||
{ | |||||
fprintf (stderr, " Missing argument for '-%c' option.\n", optopt); | |||||
} | |||||
else if (isprint (optopt)) | |||||
{ | |||||
fprintf (stderr, " Unknown option '-%c'.\n", optopt); | |||||
} | |||||
else | |||||
{ | |||||
fprintf (stderr, " Unknown option character '0x%02x'.\n", optopt & 255); | |||||
} | |||||
fprintf (stderr, " Use '-h' to see all options.\n"); | |||||
return 1; | |||||
default: | |||||
return 1; | |||||
} | |||||
} | } | ||||
switch (k) | |||||
{ | |||||
case 'h' : help (); exit (0); | |||||
case 'v' : v_opt = true; break; | |||||
case 'L' : L_opt = true; break; | |||||
case 'j' : jname = optarg; break; | |||||
case 'd' : device = optarg; break; | |||||
case 'r' : fsamp = atoi (optarg); break; | |||||
case 'p' : bsize = atoi (optarg); break; | |||||
case 'n' : nfrag = atoi (optarg); break; | |||||
case 'c' : nchan = atoi (optarg); break; | |||||
case 'Q' : rqual = atoi (optarg); break; | |||||
case 'I' : ltcor = atoi (optarg); break; | |||||
case '?': | |||||
if (optopt != ':' && strchr (clopt, optopt)) | |||||
{ | |||||
fprintf (stderr, " Missing argument for '-%c' option.\n", optopt); | |||||
} | |||||
else if (isprint (optopt)) | |||||
{ | |||||
fprintf (stderr, " Unknown option '-%c'.\n", optopt); | |||||
} | |||||
else | |||||
{ | |||||
fprintf (stderr, " Unknown option character '0x%02x'.\n", optopt & 255); | |||||
} | |||||
fprintf (stderr, " Use '-h' to see all options.\n"); | |||||
return 1; | |||||
default: | |||||
return 1; | |||||
} | |||||
return 0; | |||||
} | } | ||||
return 0; | |||||
} | |||||
static int parse_options (const char* load_init) | |||||
{ | |||||
int parse_options (const char* load_init) | |||||
{ | |||||
int argsz; | int argsz; | ||||
int argc = 0; | int argc = 0; | ||||
const char** argv; | const char** argv; | ||||
@@ -127,8 +153,8 @@ static int parse_options (const char* load_init) | |||||
char* ptr = args; | char* ptr = args; | ||||
char* savep; | char* savep; | ||||
if (!load_init) { | |||||
return 0; | |||||
if (!load_init) { | |||||
return 0; | |||||
} | } | ||||
argsz = 8; /* random guess at "maxargs" */ | argsz = 8; /* random guess at "maxargs" */ | ||||
@@ -137,149 +163,166 @@ static int parse_options (const char* load_init) | |||||
argv[argc++] = APPNAME; | argv[argc++] = APPNAME; | ||||
while (1) { | while (1) { | ||||
if ((token = strtok_r (ptr, " ", &savep)) == NULL) { | |||||
break; | |||||
} | |||||
if (argc == argsz) { | |||||
argsz *= 2; | |||||
argv = (const char **) realloc (argv, sizeof (char *) * argsz); | |||||
} | |||||
argv[argc++] = token; | |||||
ptr = NULL; | |||||
if ((token = strtok_r (ptr, " ", &savep)) == NULL) { | |||||
break; | |||||
} | |||||
if (argc == argsz) { | |||||
argsz *= 2; | |||||
argv = (const char **) realloc (argv, sizeof (char *) * argsz); | |||||
} | |||||
argv[argc++] = token; | |||||
ptr = NULL; | |||||
} | } | ||||
return procoptions (argc, argv); | return procoptions (argc, argv); | ||||
} | |||||
static void printinfo (void) | |||||
{ | |||||
int n; | |||||
double e, r; | |||||
Jdata *J; | |||||
} | |||||
n = 0; | |||||
e = r = 0; | |||||
while (infoq.rd_avail ()) | |||||
void printinfo (void) | |||||
{ | { | ||||
J = infoq.rd_datap (); | |||||
if (J->_state == Jackclient::TERM) | |||||
{ | |||||
printf ("Fatal error condition, terminating.\n"); | |||||
stop = true; | |||||
return; | |||||
} | |||||
else if (J->_state == Jackclient::WAIT) | |||||
{ | |||||
printf ("Detected excessive timing errors, waiting 15 seconds.\n"); | |||||
printf ("This may happen with current Jack1 after freewheeling.\n"); | |||||
n = 0; | |||||
} | |||||
else if (J->_state == Jackclient::SYNC0) | |||||
{ | |||||
printf ("Starting synchronisation.\n"); | |||||
} | |||||
else if (v_opt) | |||||
{ | |||||
n++; | |||||
e += J->_error; | |||||
r += J->_ratio; | |||||
} | |||||
infoq.rd_commit (); | |||||
} | |||||
if (n) printf ("%8.3lf %10.6lf\n", e / n, r / n); | |||||
} | |||||
int n; | |||||
double e, r; | |||||
Jdata *J; | |||||
n = 0; | |||||
e = r = 0; | |||||
while (infoq->rd_avail ()) | |||||
{ | |||||
J = infoq->rd_datap (); | |||||
if (J->_state == Jackclient::TERM) | |||||
{ | |||||
printf ("Fatal error condition, terminating.\n"); | |||||
stop = true; | |||||
return; | |||||
} | |||||
else if (J->_state == Jackclient::WAIT) | |||||
{ | |||||
printf ("Detected excessive timing errors, waiting 15 seconds.\n"); | |||||
printf ("This may happen with current Jack1 after freewheeling.\n"); | |||||
n = 0; | |||||
} | |||||
else if (J->_state == Jackclient::SYNC0) | |||||
{ | |||||
printf ("Starting synchronisation.\n"); | |||||
} | |||||
else if (v_opt) | |||||
{ | |||||
n++; | |||||
e += J->_error; | |||||
r += J->_ratio; | |||||
} | |||||
infoq->rd_commit (); | |||||
} | |||||
if (n) printf ("%8.3lf %10.6lf\n", e / n, r / n); | |||||
} | |||||
static Alsa_pcmi *A = 0; | |||||
static Alsathread *C = 0; | |||||
static Jackclient *J = 0; | |||||
extern "C" { | |||||
Alsa_pcmi *A; | |||||
Alsathread *C; | |||||
Jackclient *J; | |||||
int | |||||
jack_initialize (jack_client_t* client, const char* load_init) | |||||
{ | |||||
int k, k_del, opts; | |||||
double t_jack; | |||||
double t_alsa; | |||||
double t_del; | |||||
if (parse_options (load_init)) { | |||||
fprintf (stderr, "parse options failed\n"); | |||||
return 1; | |||||
} | |||||
public: | |||||
if (device == 0) help (); | |||||
if (rqual < 16) rqual = 16; | |||||
if (rqual > 96) rqual = 96; | |||||
if ((fsamp && fsamp < 8000) || (bsize && bsize < 16) || (nfrag < 2) || (nchan < 1)) | |||||
int | |||||
jack_initialize (jack_client_t* client, const char* load_init) | |||||
{ | { | ||||
fprintf (stderr, "Illegal parameter value(s).\n"); | |||||
return 1; | |||||
} | |||||
int k, k_del, opts; | |||||
double t_jack; | |||||
double t_alsa; | |||||
double t_del; | |||||
if (parse_options (load_init)) { | |||||
fprintf (stderr, "parse options failed\n"); | |||||
return 1; | |||||
} | |||||
J = new Jackclient (client, 0, Jackclient::CAPT, 0); | |||||
usleep (100000); | |||||
if (device == 0) help (); | |||||
if (rqual < 16) rqual = 16; | |||||
if (rqual > 96) rqual = 96; | |||||
if ((fsamp && fsamp < 8000) || (bsize && bsize < 16) || (nfrag < 2) || (nchan < 1)) | |||||
{ | |||||
fprintf (stderr, "Illegal parameter value(s).\n"); | |||||
return 1; | |||||
} | |||||
/* if SR and/or bufsize are unspecified, use the same values | |||||
as the JACK server. | |||||
*/ | |||||
if (fsamp == 0) | |||||
{ | |||||
fsamp = J->fsamp(); | |||||
} | |||||
J = new Jackclient (client, 0, Jackclient::CAPT, 0, this); | |||||
usleep (100000); | |||||
if (bsize == 0) | |||||
{ | |||||
bsize = J->bsize(); | |||||
} | |||||
/* if SR and/or bufsize are unspecified, use the same values | |||||
as the JACK server. | |||||
*/ | |||||
if (fsamp == 0) | |||||
{ | |||||
fsamp = J->fsamp(); | |||||
} | |||||
opts = 0; | |||||
if (v_opt) opts |= Alsa_pcmi::DEBUG_ALL; | |||||
if (L_opt) opts |= Alsa_pcmi::FORCE_16B | Alsa_pcmi::FORCE_2CH; | |||||
A = new Alsa_pcmi (0, device, 0, fsamp, bsize, nfrag, opts); | |||||
if (A->state ()) | |||||
{ | |||||
fprintf (stderr, "Can't open ALSA capture device '%s'.\n", device); | |||||
return 1; | |||||
if (bsize == 0) | |||||
{ | |||||
bsize = J->bsize(); | |||||
} | |||||
opts = 0; | |||||
if (v_opt) opts |= Alsa_pcmi::DEBUG_ALL; | |||||
if (L_opt) opts |= Alsa_pcmi::FORCE_16B | Alsa_pcmi::FORCE_2CH; | |||||
A = new Alsa_pcmi (0, device, 0, fsamp, bsize, nfrag, opts); | |||||
if (A->state ()) | |||||
{ | |||||
fprintf (stderr, "Can't open ALSA capture device '%s'.\n", device); | |||||
return 1; | |||||
} | |||||
if (v_opt) A->printinfo (); | |||||
if (nchan > A->ncapt ()) | |||||
{ | |||||
nchan = A->ncapt (); | |||||
fprintf (stderr, "Warning: only %d channels are available.\n", nchan); | |||||
} | |||||
C = new Alsathread (A, Alsathread::CAPT); | |||||
J->register_ports (nchan); | |||||
t_alsa = (double) bsize / fsamp; | |||||
if (t_alsa < 1e-3) t_alsa = 1e-3; | |||||
t_jack = (double) J->bsize () / J->fsamp (); | |||||
t_del = 1.5 * t_alsa + t_jack; | |||||
k_del = (int)(t_del * fsamp); | |||||
for (k = 256; k < k_del + J->bsize (); k *= 2); | |||||
audioq = new Lfq_audio (k, nchan); | |||||
C->start (audioq, commq, alsaq, J->rprio () + 10); | |||||
J->start (audioq, commq, alsaq, infoq, J->fsamp () / (double) fsamp, k_del, ltcor, rqual); | |||||
return 0; | |||||
} | } | ||||
if (v_opt) A->printinfo (); | |||||
if (nchan > A->ncapt ()) | |||||
void jack_finish (void* arg) | |||||
{ | { | ||||
nchan = A->ncapt (); | |||||
fprintf (stderr, "Warning: only %d channels are available.\n", nchan); | |||||
commq->wr_int32 (Alsathread::TERM); | |||||
usleep (100000); | |||||
delete C; | |||||
delete A; | |||||
delete J; | |||||
delete audioq; | |||||
} | } | ||||
C = new Alsathread (A, Alsathread::CAPT); | |||||
J->register_ports (nchan); | |||||
t_alsa = (double) bsize / fsamp; | |||||
if (t_alsa < 1e-3) t_alsa = 1e-3; | |||||
t_jack = (double) J->bsize () / J->fsamp (); | |||||
t_del = 1.5 * t_alsa + t_jack; | |||||
k_del = (int)(t_del * fsamp); | |||||
for (k = 256; k < k_del + J->bsize (); k *= 2); | |||||
audioq = new Lfq_audio (k, nchan); | |||||
C->start (audioq, &commq, &alsaq, J->rprio () + 10); | |||||
J->start (audioq, &commq, &alsaq, &infoq, J->fsamp () / (double) fsamp, k_del, ltcor, rqual); | |||||
return 0; | |||||
}; | |||||
extern "C" { | |||||
int | |||||
jack_initialize (jack_client_t* client, const char* load_init) | |||||
{ | |||||
zita_a2j *c = new zita_a2j(); | |||||
c->jack_initialize(client, load_init); | |||||
} | } | ||||
void jack_finish (void* arg) | void jack_finish (void* arg) | ||||
{ | { | ||||
commq.wr_int32 (Alsathread::TERM); | |||||
usleep (100000); | |||||
delete C; | |||||
delete A; | |||||
delete J; | |||||
delete audioq; | |||||
Jackclient *J = (Jackclient *)arg; | |||||
zita_a2j *c = (zita_a2j *)J->getarg(); | |||||
c->jack_finish(arg); | |||||
delete c; | |||||
} | } | ||||
} /* extern "C" */ | } /* extern "C" */ |
@@ -27,25 +27,7 @@ | |||||
#include "jackclient.h" | #include "jackclient.h" | ||||
#include "lfqueue.h" | #include "lfqueue.h" | ||||
static Lfq_int32 commq (16); | |||||
static Lfq_adata alsaq (256); | |||||
static Lfq_jdata infoq (256); | |||||
static Lfq_audio *audioq = 0; | |||||
static bool stop = false; | |||||
static const char *clopt = "hvLj:d:r:p:n:c:Q:O:"; | |||||
static bool v_opt = false; | |||||
static bool L_opt = false; | |||||
static const char *jname = APPNAME; | |||||
static const char *device = 0; | |||||
static int fsamp = 0; | |||||
static int bsize = 0; | |||||
static int nfrag = 2; | |||||
static int nchan = 2; | |||||
static int rqual = 48; | |||||
static int ltcor = 0; | |||||
static const char *clopt = "hvLj:d:r:p:n:c:Q:I:"; | |||||
static void help (void) | static void help (void) | ||||
{ | { | ||||
@@ -68,58 +50,102 @@ static void help (void) | |||||
exit (1); | exit (1); | ||||
} | } | ||||
static int procoptions (int ac, const char *av []) | |||||
class zita_j2a | |||||
{ | { | ||||
int k; | |||||
optind = 1; | |||||
opterr = 0; | |||||
while ((k = getopt (ac, (char **) av, (char *) clopt)) != -1) | |||||
Lfq_int32 *commq; | |||||
Lfq_adata *alsaq; | |||||
Lfq_jdata *infoq; | |||||
Lfq_audio *audioq; | |||||
bool stop; | |||||
bool v_opt; | |||||
bool L_opt; | |||||
char *jname; | |||||
char *device; | |||||
int fsamp; | |||||
int bsize; | |||||
int nfrag; | |||||
int nchan; | |||||
int rqual; | |||||
int ltcor; | |||||
public: | |||||
zita_j2a() | |||||
{ | |||||
commq = new Lfq_int32(16); | |||||
alsaq = new Lfq_adata(256); | |||||
infoq = new Lfq_jdata(256); | |||||
audioq = 0; | |||||
stop = false; | |||||
v_opt = false; | |||||
L_opt = false; | |||||
jname = strdup(APPNAME); | |||||
device = 0; | |||||
fsamp = 0; | |||||
bsize = 0; | |||||
nfrag = 2; | |||||
nchan = 2; | |||||
rqual = 48; | |||||
ltcor = 0; | |||||
A = 0; | |||||
P = 0; | |||||
J = 0; | |||||
} | |||||
private: | |||||
int procoptions (int ac, const char *av []) | |||||
{ | { | ||||
if (optarg && (*optarg == '-')) | |||||
int k; | |||||
optind = 1; | |||||
opterr = 0; | |||||
while ((k = getopt (ac, (char **) av, (char *) clopt)) != -1) | |||||
{ | { | ||||
fprintf (stderr, " Missing argument for '-%c' option.\n", k); | |||||
fprintf (stderr, " Use '-h' to see all options.\n"); | |||||
exit (1); | |||||
if (optarg && (*optarg == '-')) | |||||
{ | |||||
fprintf (stderr, " Missing argument for '-%c' option.\n", k); | |||||
fprintf (stderr, " Use '-h' to see all options.\n"); | |||||
exit (1); | |||||
} | |||||
switch (k) | |||||
{ | |||||
case 'h' : help (); exit (0); | |||||
case 'v' : v_opt = true; break; | |||||
case 'L' : L_opt = true; break; | |||||
case 'j' : jname = optarg; break; | |||||
case 'd' : device = optarg; break; | |||||
case 'r' : fsamp = atoi (optarg); break; | |||||
case 'p' : bsize = atoi (optarg); break; | |||||
case 'n' : nfrag = atoi (optarg); break; | |||||
case 'c' : nchan = atoi (optarg); break; | |||||
case 'Q' : rqual = atoi (optarg); break; | |||||
case 'O' : ltcor = atoi (optarg); break; | |||||
case '?': | |||||
if (optopt != ':' && strchr (clopt, optopt)) | |||||
{ | |||||
fprintf (stderr, " Missing argument for '-%c' option.\n", optopt); | |||||
} | |||||
else if (isprint (optopt)) | |||||
{ | |||||
fprintf (stderr, " Unknown option '-%c'.\n", optopt); | |||||
} | |||||
else | |||||
{ | |||||
fprintf (stderr, " Unknown option character '0x%02x'.\n", optopt & 255); | |||||
} | |||||
fprintf (stderr, " Use '-h' to see all options.\n"); | |||||
return 1; | |||||
default: | |||||
return 1; | |||||
} | |||||
} | } | ||||
switch (k) | |||||
{ | |||||
case 'h' : help (); exit (0); | |||||
case 'v' : v_opt = true; break; | |||||
case 'L' : L_opt = true; break; | |||||
case 'j' : jname = optarg; break; | |||||
case 'd' : device = optarg; break; | |||||
case 'r' : fsamp = atoi (optarg); break; | |||||
case 'p' : bsize = atoi (optarg); break; | |||||
case 'n' : nfrag = atoi (optarg); break; | |||||
case 'c' : nchan = atoi (optarg); break; | |||||
case 'Q' : rqual = atoi (optarg); break; | |||||
case 'O' : ltcor = atoi (optarg); break; | |||||
case '?': | |||||
if (optopt != ':' && strchr (clopt, optopt)) | |||||
{ | |||||
fprintf (stderr, " Missing argument for '-%c' option.\n", optopt); | |||||
} | |||||
else if (isprint (optopt)) | |||||
{ | |||||
fprintf (stderr, " Unknown option '-%c'.\n", optopt); | |||||
} | |||||
else | |||||
{ | |||||
fprintf (stderr, " Unknown option character '0x%02x'.\n", optopt & 255); | |||||
} | |||||
fprintf (stderr, " Use '-h' to see all options.\n"); | |||||
return 1; | |||||
default: | |||||
return 1; | |||||
} | |||||
} | |||||
return 0; | |||||
} | |||||
return 0; | |||||
} | |||||
static int parse_options (const char* load_init) | |||||
{ | |||||
int parse_options (const char* load_init) | |||||
{ | |||||
int argsz; | int argsz; | ||||
int argc = 0; | int argc = 0; | ||||
const char** argv; | const char** argv; | ||||
@@ -128,8 +154,8 @@ static int parse_options (const char* load_init) | |||||
char* ptr = args; | char* ptr = args; | ||||
char* savep; | char* savep; | ||||
if (!load_init) { | |||||
return 0; | |||||
if (!load_init) { | |||||
return 0; | |||||
} | } | ||||
argsz = 8; /* random guess at "maxargs" */ | argsz = 8; /* random guess at "maxargs" */ | ||||
@@ -138,144 +164,162 @@ static int parse_options (const char* load_init) | |||||
argv[argc++] = APPNAME; | argv[argc++] = APPNAME; | ||||
while (1) { | while (1) { | ||||
if ((token = strtok_r (ptr, " ", &savep)) == NULL) { | |||||
break; | |||||
} | |||||
if (argc == argsz) { | |||||
argsz *= 2; | |||||
argv = (const char **) realloc (argv, sizeof (char *) * argsz); | |||||
} | |||||
argv[argc++] = token; | |||||
ptr = NULL; | |||||
if ((token = strtok_r (ptr, " ", &savep)) == NULL) { | |||||
break; | |||||
} | |||||
if (argc == argsz) { | |||||
argsz *= 2; | |||||
argv = (const char **) realloc (argv, sizeof (char *) * argsz); | |||||
} | |||||
argv[argc++] = token; | |||||
ptr = NULL; | |||||
} | } | ||||
return procoptions (argc, argv); | return procoptions (argc, argv); | ||||
} | |||||
static void printinfo (void) | |||||
{ | |||||
int n; | |||||
double e, r; | |||||
Jdata *J; | |||||
} | |||||
n = 0; | |||||
e = r = 0; | |||||
while (infoq.rd_avail ()) | |||||
void printinfo (void) | |||||
{ | { | ||||
J = infoq.rd_datap (); | |||||
if (J->_state == Jackclient::TERM) | |||||
{ | |||||
printf ("Fatal error condition, terminating.\n"); | |||||
stop = true; | |||||
return; | |||||
} | |||||
else if (J->_state == Jackclient::WAIT) | |||||
{ | |||||
printf ("Detected excessive timing errors, waiting 15 seconds.\n"); | |||||
printf ("This may happen with current Jack1 after freewheeling.\n"); | |||||
n = 0; | |||||
} | |||||
else if (J->_state == Jackclient::SYNC0) | |||||
{ | |||||
printf ("Starting synchronisation.\n"); | |||||
} | |||||
else if (v_opt) | |||||
{ | |||||
n++; | |||||
e += J->_error; | |||||
r += J->_ratio; | |||||
} | |||||
infoq.rd_commit (); | |||||
int n; | |||||
double e, r; | |||||
Jdata *J; | |||||
n = 0; | |||||
e = r = 0; | |||||
while (infoq->rd_avail ()) | |||||
{ | |||||
J = infoq->rd_datap (); | |||||
if (J->_state == Jackclient::TERM) | |||||
{ | |||||
printf ("Fatal error condition, terminating.\n"); | |||||
stop = true; | |||||
return; | |||||
} | |||||
else if (J->_state == Jackclient::WAIT) | |||||
{ | |||||
printf ("Detected excessive timing errors, waiting 15 seconds.\n"); | |||||
printf ("This may happen with current Jack1 after freewheeling.\n"); | |||||
n = 0; | |||||
} | |||||
else if (J->_state == Jackclient::SYNC0) | |||||
{ | |||||
printf ("Starting synchronisation.\n"); | |||||
} | |||||
else if (v_opt) | |||||
{ | |||||
n++; | |||||
e += J->_error; | |||||
r += J->_ratio; | |||||
} | |||||
infoq->rd_commit (); | |||||
} | |||||
if (n) printf ("%8.3lf %10.6lf\n", e / n, r / n); | |||||
} | } | ||||
if (n) printf ("%8.3lf %10.6lf\n", e / n, r / n); | |||||
} | |||||
Alsa_pcmi *A = 0; | |||||
Alsathread *P = 0; | |||||
Jackclient *J = 0; | |||||
Alsa_pcmi *A; | |||||
Alsathread *P; | |||||
Jackclient *J; | |||||
public: | |||||
extern "C" { | |||||
int jack_initialize (jack_client_t* client, const char* load_init) | |||||
{ | |||||
int k, k_del, opts; | |||||
double t_jack; | |||||
double t_alsa; | |||||
double t_del; | |||||
int jack_initialize (jack_client_t* client, const char* load_init) | |||||
{ | |||||
int k, k_del, opts; | |||||
double t_jack; | |||||
double t_alsa; | |||||
double t_del; | |||||
if (parse_options (load_init)) { | |||||
return 1; | |||||
} | |||||
if (parse_options (load_init)) { | |||||
if (device == 0) help (); | |||||
if (rqual < 16) rqual = 16; | |||||
if (rqual > 96) rqual = 96; | |||||
if ((fsamp && fsamp < 8000) || (bsize && bsize < 16) || (nfrag < 2) || (nchan < 1)) | |||||
{ | |||||
fprintf (stderr, "Illegal parameter value(s).\n"); | |||||
return 1; | return 1; | ||||
} | |||||
} | |||||
if (device == 0) help (); | |||||
if (rqual < 16) rqual = 16; | |||||
if (rqual > 96) rqual = 96; | |||||
if ((fsamp && fsamp < 8000) || (bsize && bsize < 16) || (nfrag < 2) || (nchan < 1)) | |||||
{ | |||||
fprintf (stderr, "Illegal parameter value(s).\n"); | |||||
return 1; | |||||
} | |||||
J = new Jackclient (client, 0, Jackclient::PLAY, 0, this); | |||||
usleep (100000); | |||||
J = new Jackclient (client, 0, Jackclient::PLAY, 0); | |||||
usleep (100000); | |||||
/* if SR and/or bufsize are unspecified, use the same values | |||||
as the JACK server. | |||||
*/ | |||||
/* if SR and/or bufsize are unspecified, use the same values | |||||
as the JACK server. | |||||
*/ | |||||
if (fsamp == 0) | |||||
{ | |||||
fsamp = J->fsamp(); | |||||
} | |||||
if (fsamp == 0) | |||||
{ | |||||
fsamp = J->fsamp(); | |||||
} | |||||
if (bsize == 0) | |||||
{ | |||||
bsize = J->bsize(); | |||||
} | |||||
if (bsize == 0) | |||||
{ | |||||
bsize = J->bsize(); | |||||
} | |||||
opts = 0; | |||||
if (v_opt) opts |= Alsa_pcmi::DEBUG_ALL; | |||||
if (L_opt) opts |= Alsa_pcmi::FORCE_16B | Alsa_pcmi::FORCE_2CH; | |||||
A = new Alsa_pcmi (device, 0, 0, fsamp, bsize, nfrag, opts); | |||||
if (A->state ()) | |||||
{ | |||||
fprintf (stderr, "Can't open ALSA playback device '%s'.\n", device); | |||||
return 1; | |||||
opts = 0; | |||||
if (v_opt) opts |= Alsa_pcmi::DEBUG_ALL; | |||||
if (L_opt) opts |= Alsa_pcmi::FORCE_16B | Alsa_pcmi::FORCE_2CH; | |||||
A = new Alsa_pcmi (device, 0, 0, fsamp, bsize, nfrag, opts); | |||||
if (A->state ()) | |||||
{ | |||||
fprintf (stderr, "Can't open ALSA playback device '%s'.\n", device); | |||||
return 1; | |||||
} | |||||
if (v_opt) A->printinfo (); | |||||
if (nchan > A->nplay ()) | |||||
{ | |||||
nchan = A->nplay (); | |||||
fprintf (stderr, "Warning: only %d channels are available.\n", nchan); | |||||
} | |||||
P = new Alsathread (A, Alsathread::PLAY); | |||||
J->register_ports (nchan); | |||||
t_alsa = (double) bsize / fsamp; | |||||
if (t_alsa < 1e-3) t_alsa = 1e-3; | |||||
t_jack = (double) J->bsize () / J->fsamp (); | |||||
t_del = 1.5 * t_alsa + t_jack; | |||||
k_del = (int)(t_del * fsamp); | |||||
for (k = 256; k < k_del + J->bsize (); k *= 2); | |||||
audioq = new Lfq_audio (k, nchan); | |||||
P->start (audioq, commq, alsaq, J->rprio () + 10); | |||||
J->start (audioq, commq, alsaq, infoq, (double) fsamp / J->fsamp (), k_del, ltcor, rqual); | |||||
return 0; | |||||
} | } | ||||
if (v_opt) A->printinfo (); | |||||
if (nchan > A->nplay ()) | |||||
void jack_finish (void* arg) | |||||
{ | { | ||||
nchan = A->nplay (); | |||||
fprintf (stderr, "Warning: only %d channels are available.\n", nchan); | |||||
commq->wr_int32 (Alsathread::TERM); | |||||
usleep (100000); | |||||
delete P; | |||||
delete A; | |||||
delete J; | |||||
delete audioq; | |||||
} | } | ||||
P = new Alsathread (A, Alsathread::PLAY); | |||||
J->register_ports (nchan); | |||||
t_alsa = (double) bsize / fsamp; | |||||
if (t_alsa < 1e-3) t_alsa = 1e-3; | |||||
t_jack = (double) J->bsize () / J->fsamp (); | |||||
t_del = 1.5 * t_alsa + t_jack; | |||||
k_del = (int)(t_del * fsamp); | |||||
for (k = 256; k < k_del + J->bsize (); k *= 2); | |||||
audioq = new Lfq_audio (k, nchan); | |||||
}; | |||||
P->start (audioq, &commq, &alsaq, J->rprio () + 10); | |||||
J->start (audioq, &commq, &alsaq, &infoq, (double) fsamp / J->fsamp (), k_del, ltcor, rqual); | |||||
extern "C" { | |||||
return 0; | |||||
int | |||||
jack_initialize (jack_client_t* client, const char* load_init) | |||||
{ | |||||
zita_j2a *c = new zita_j2a(); | |||||
c->jack_initialize(client, load_init); | |||||
} | } | ||||
void jack_finish (void* arg) | void jack_finish (void* arg) | ||||
{ | { | ||||
commq.wr_int32 (Alsathread::TERM); | |||||
usleep (100000); | |||||
delete P; | |||||
delete A; | |||||
delete J; | |||||
delete audioq; | |||||
Jackclient *J = (Jackclient *)arg; | |||||
zita_j2a *c = (zita_j2a *)J->getarg(); | |||||
c->jack_finish(arg); | |||||
delete c; | |||||
} | } | ||||
} /* extern "C" */ | } /* extern "C" */ |