Rivendellaudio/cae/cae_jack.cpp

1691 lines
46 KiB
C++

// cae_jack.cpp
//
// The JACK Driver for the Core Audio Engine component of Rivendell
//
// (C) Copyright 2002-2019 Fred Gleason <fredg@paravelsystems.com>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include <math.h>
#include <samplerate.h>
#include <qsignalmapper.h>
#include <rd.h>
#include <rdapplication.h>
#include <rddatedecode.h>
#include <rddb.h>
#include <rdescape_string.h>
#include <rdringbuffer.h>
#include <rdprofile.h>
#include <rdmeteraverage.h>
#include <cae.h>
#ifdef JACK
//
// Callback Variables
//
jack_client_t *jack_client;
RDMeterAverage *jack_input_meter[RD_MAX_PORTS][2];
RDMeterAverage *jack_output_meter[RD_MAX_PORTS][2];
RDMeterAverage *jack_stream_output_meter[RD_MAX_STREAMS][2];
volatile jack_default_audio_sample_t
jack_input_volume[RD_MAX_PORTS];
volatile jack_default_audio_sample_t
jack_output_volume[RD_MAX_PORTS][RD_MAX_STREAMS];
volatile jack_default_audio_sample_t
jack_passthrough_volume[RD_MAX_PORTS][RD_MAX_PORTS];
volatile jack_default_audio_sample_t jack_input_vox[RD_MAX_PORTS];
jack_port_t *jack_input_port[RD_MAX_PORTS][2];
jack_port_t *jack_output_port[RD_MAX_PORTS][2];
volatile int jack_input_channels[RD_MAX_PORTS];
volatile int jack_output_channels[RD_MAX_STREAMS];
volatile jack_default_audio_sample_t *jack_input_buffer[RD_MAX_PORTS][2];
volatile jack_default_audio_sample_t *jack_output_buffer[RD_MAX_PORTS][2];
RDRingBuffer *jack_play_ring[RD_MAX_STREAMS];
RDRingBuffer *jack_record_ring[RD_MAX_PORTS];
volatile bool jack_playing[RD_MAX_STREAMS];
volatile bool jack_stopping[RD_MAX_STREAMS];
volatile bool jack_eof[RD_MAX_STREAMS];
volatile bool jack_recording[RD_MAX_PORTS];
volatile bool jack_ready[RD_MAX_PORTS];
volatile int jack_output_pos[RD_MAX_STREAMS];
volatile unsigned jack_output_sample_rate[RD_MAX_STREAMS];
volatile unsigned jack_sample_rate;
int jack_input_mode[RD_MAX_CARDS][RD_MAX_PORTS];
int jack_card_process; // local copy of object member jack_card, for use by the callback process.
//
// Callback Buffers
//
jack_default_audio_sample_t jack_callback_buffer[RINGBUFFER_SIZE];
int JackProcess(jack_nframes_t nframes, void *arg)
{
unsigned n=0;
jack_default_audio_sample_t in_meter[2];
jack_default_audio_sample_t out_meter[2];
jack_default_audio_sample_t stream_out_meter;
//
// Ensure Buffers are Valid
//
for(int i=0;i<RD_MAX_PORTS;i++) {
for(int j=0;j<2;j++) {
if(jack_input_port[i][j]!=NULL) {
jack_input_buffer[i][j]=(jack_default_audio_sample_t *)
jack_port_get_buffer(jack_input_port[i][j],nframes);
}
if(jack_output_port[i][j]!=NULL) {
jack_output_buffer[i][j]=(jack_default_audio_sample_t *)
jack_port_get_buffer(jack_output_port[i][j],nframes);
}
}
}
//
// Zero Output Ports
//
for(int i=0;i<RD_MAX_PORTS;i++) {
for(int j=0;j<2;j++) {
if(jack_output_port[i][j]!=NULL) {
for(unsigned k=0;k<nframes;k++) {
jack_output_buffer[i][j][k]=0.0;
}
}
}
}
//
// Process Passthroughs
//
for(int i=0;i<RD_MAX_PORTS;i++) {
for(int j=0;j<RD_MAX_PORTS;j++) {
if(jack_passthrough_volume[i][j]>0.0) {
for(int k=0;k<2;k++) {
if((jack_output_port[j][k]!=NULL)&&(jack_input_port[i][k]!=NULL)) {
for(unsigned l=0;l<nframes;l++) {
jack_output_buffer[j][k][l]+=
jack_input_buffer[i][k][l]*jack_passthrough_volume[i][j];
}
}
}
}
}
}
//
// Process Input Streams
//
for(int i=0;i<RD_MAX_PORTS;i++) {
if(jack_input_port[i][0]!=NULL) {
if(jack_recording[i]) {
switch(jack_input_channels[i]) {
case 1: // mono
for(unsigned j=0;j<nframes;j++) {
switch(jack_input_mode[jack_card_process][i]) {
case 3: // R only
jack_callback_buffer[j]=jack_input_volume[i]*
jack_input_buffer[i][1][j];
break;
case 2: // L only
jack_callback_buffer[j]=jack_input_volume[i]*
jack_input_buffer[i][0][j];
break;
case 1: // swap, sum R+L
case 0: // normal, sum L+R
default:
jack_callback_buffer[j]=jack_input_volume[i]*
(jack_input_buffer[i][0][j]+jack_input_buffer[i][1][j]);
break;
}
} // for nframes
n=jack_record_ring[i]->
write((char *)jack_callback_buffer,
nframes*sizeof(jack_default_audio_sample_t))/
sizeof(jack_default_audio_sample_t);
break;
case 2: // stereo
for(unsigned j=0;j<nframes;j++) {
switch(jack_input_mode[jack_card_process][i]) {
case 3: // R only
memset(&jack_callback_buffer[2*j],0,
sizeof(jack_input_buffer[i][0][j]));
jack_callback_buffer[2*j+1]=jack_input_volume[i]*
jack_input_buffer[i][1][j];
break;
case 2: // L only
jack_callback_buffer[2*j]=jack_input_volume[i]*
jack_input_buffer[i][0][j];
memset(&jack_callback_buffer[2*j+1],0,
sizeof(jack_input_buffer[i][1][j]));
break;
case 1: // swap
jack_callback_buffer[2*j]=jack_input_volume[i]*
jack_input_buffer[i][1][j];
jack_callback_buffer[2*j+1]=jack_input_volume[i]*
jack_input_buffer[i][0][j];
break;
case 0: // normal
default:
jack_callback_buffer[2*j]=jack_input_volume[i]*
jack_input_buffer[i][0][j];
jack_callback_buffer[2*j+1]=jack_input_volume[i]*
jack_input_buffer[i][1][j];
break;
}
} // for nframes
n=jack_record_ring[i]->
write((char *)jack_callback_buffer,
2*nframes*sizeof(jack_default_audio_sample_t))/
(2*sizeof(jack_default_audio_sample_t));
break;
}
}
}
}
//
// Process Output Streams
//
for(int i=0;i<RD_MAX_STREAMS;i++) {
if(jack_playing[i]) {
switch(jack_output_channels[i]) {
case 1:
n=jack_play_ring[i]->
read((char *)jack_callback_buffer,
nframes*sizeof(jack_default_audio_sample_t))/
sizeof(jack_default_audio_sample_t);
stream_out_meter=0.0;
for(unsigned j=0;j<n;j++) { // Stream Output Meters
if(fabsf(jack_callback_buffer[j])>stream_out_meter) {
stream_out_meter=fabsf(jack_callback_buffer[j]);
}
}
jack_stream_output_meter[i][0]->addValue(stream_out_meter);
jack_stream_output_meter[i][1]->addValue(stream_out_meter);
break;
case 2:
n=jack_play_ring[i]->
read((char *)jack_callback_buffer,
2*nframes*sizeof(jack_default_audio_sample_t))/
(2*sizeof(jack_default_audio_sample_t));
for(unsigned j=0;j<2;j++) { // Stream Output Meters
stream_out_meter=0.0;
for(unsigned k=0;k<n;k+=2) {
if(fabsf(jack_callback_buffer[k+j])>stream_out_meter) {
stream_out_meter=fabsf(jack_callback_buffer[k+j]);
}
}
jack_stream_output_meter[i][j]->addValue(stream_out_meter);
}
break;
}
for(int j=0;j<RD_MAX_PORTS;j++) {
if(jack_output_port[j][0]!=NULL) {
if(jack_output_volume[j][i]>0.0) {
switch(jack_output_channels[i]) {
case 1:
for(unsigned k=0;k<n;k++) {
jack_output_buffer[j][0][k]=
jack_output_buffer[j][0][k]+jack_output_volume[j][i]*
jack_callback_buffer[k];
jack_output_buffer[j][1][k]=
jack_output_buffer[j][1][k]+jack_output_volume[j][i]*
jack_callback_buffer[k];
}
if(n!=nframes && jack_eof[i]) {
jack_stopping[i]=true;
jack_playing[i]=false;
}
break;
case 2:
for(unsigned k=0;k<n;k++) {
jack_output_buffer[j][0][k]=
jack_output_buffer[j][0][k]+jack_output_volume[j][i]*
jack_callback_buffer[k*2];
jack_output_buffer[j][1][k]=
jack_output_buffer[j][1][k]+jack_output_volume[j][i]*
jack_callback_buffer[k*2+1];
}
if(n!=nframes && jack_eof[i]) {
jack_stopping[i]=true;
jack_playing[i]=false;
}
break;
}
}
}
}
double ratio=(double)jack_output_sample_rate[i]/(double)jack_sample_rate;
jack_output_pos[i]+=(int)(((double)n*ratio)+0.5);
}
}
//
// Process Meters
//
for(int i=0;i<RD_MAX_PORTS;i++) {
if(jack_input_port[i][0]!=NULL) {
// input meters (taking input mode into account)
in_meter[0]=0.0;
in_meter[1]=0.0;
for(unsigned k=0;k<nframes;k++) {
switch(jack_input_mode[jack_card_process][i]) {
case 3: // R only
if(jack_input_buffer[i][1][k]>in_meter[1])
in_meter[1]=jack_input_buffer[i][1][k];
break;
case 2: // L only
if(jack_input_buffer[i][0][k]>in_meter[0])
in_meter[0]=jack_input_buffer[i][0][k];
break;
case 1: // swap
if(jack_input_buffer[i][0][k]>in_meter[1])
in_meter[1]=jack_input_buffer[i][0][k];
if(jack_input_buffer[i][1][k]>in_meter[0])
in_meter[0]=jack_input_buffer[i][1][k];
break;
case 0: // normal
default:
if(jack_input_buffer[i][0][k]>in_meter[0])
in_meter[0]=jack_input_buffer[i][0][k];
if(jack_input_buffer[i][1][k]>in_meter[1])
in_meter[1]=jack_input_buffer[i][1][k];
break;
}
} // for nframes
jack_input_meter[i][0]->addValue(in_meter[0]);
jack_input_meter[i][1]->addValue(in_meter[1]);
}
if(jack_output_port[i][0]!=NULL) {
// output meters
for(int j=0;j<2;j++) {
out_meter[j]=0.0;
for(unsigned k=0;k<nframes;k++) {
if(jack_output_buffer[i][j][k]>out_meter[j])
out_meter[j]=jack_output_buffer[i][j][k];
}
jack_output_meter[i][j]->addValue(out_meter[j]);
}
}
} // for RD_MAX_PORTS
return 0;
}
int JackSampleRate(jack_nframes_t nframes, void *arg)
{
jack_sample_rate=nframes;
return 0;
}
void JackError(const char *desc)
{
fprintf(stderr,"caed: Jack error: %s\n",desc);
}
void JackShutdown(void *arg)
{
}
void JackInitCallback()
{
int avg_periods=(int)(330.0*jack_get_sample_rate(jack_client)/
(1000.0*jack_get_buffer_size(jack_client)));
for(int i=0;i<RD_MAX_PORTS;i++) {
jack_recording[i]=false;
jack_ready[i]=false;
jack_input_volume[i]=1.0;
jack_input_vox[i]=0.0;
for(int j=0;j<2;j++) {
jack_input_meter[i][j]=new RDMeterAverage(avg_periods);
jack_output_meter[i][j]=new RDMeterAverage(avg_periods);
jack_input_buffer[i][j]=NULL;
jack_output_buffer[i][j]=NULL;
}
for(int j=0;j<RD_MAX_STREAMS;j++) {
jack_output_volume[i][j]=1.0;
}
for(int j=0;j<RD_MAX_PORTS;j++) {
jack_passthrough_volume[i][j]=0.0;
}
jack_record_ring[i]=NULL;
}
for(int i=0;i<RD_MAX_STREAMS;i++) {
jack_play_ring[i]=NULL;
jack_playing[i]=false;
for(int j=0;j<2;j++) {
jack_stream_output_meter[i][j]=new RDMeterAverage(avg_periods);
}
}
}
#endif // JACK
void MainObject::jackStopTimerData(int stream)
{
#ifdef JACK
jackStopPlayback(jack_card,stream);
statePlayUpdate(jack_card,stream,2);
#endif // JACK
}
void MainObject::jackFadeTimerData(int stream)
{
#ifdef JACK
int level;
if(!jack_fade_up[stream]) {
level=jack_output_volume_db[jack_fade_port[stream]][stream]-
jack_fade_increment[stream];
if(level<=jack_fade_volume_db[stream]) {
level=jack_fade_volume_db[stream];
jack_fade_timer[stream]->stop();
}
}
else {
level=jack_output_volume_db[jack_fade_port[stream]][stream]+
jack_fade_increment[stream];
if(level>=jack_fade_volume_db[stream]) {
level=jack_fade_volume_db[stream];
jack_fade_timer[stream]->stop();
}
}
jackSetOutputVolume(jack_card,stream,jack_fade_port[stream],level);
#endif // JACK
}
void MainObject::jackRecordTimerData(int stream)
{
#ifdef JACK
jackStopRecord(jack_card,stream);
stateRecordUpdate(jack_card,stream,2);
#endif // JACK
}
void MainObject::jackClientStartData()
{
#ifdef JACK
QString sql=QString("select ")+
"DESCRIPTION,"+ // 00
"COMMAND_LINE "+ // 01
"from JACK_CLIENTS where "+
"STATION_NAME=\""+RDEscapeString(rd_config->stationName())+"\"";
RDSqlQuery *q=new RDSqlQuery(sql);
while(q->next()) {
QString cmd=RDDateDecode(q->value(1).toString(),QDate::currentDate(),
cae_station,rd_config,
rd_config->provisioningServiceName(rd_config->stationName()));
QStringList args=cmd.split(" ",QString::SkipEmptyParts);
QString program=args.at(0);
args.removeFirst();
jack_clients.push_back(new QProcess(this));
jack_clients.back()->start(program,args);
if(jack_clients.back()->waitForStarted()) {
RDApplication::syslog(rd_config,LOG_INFO,"started JACK Client \"%s\"",
(const char *)q->value(0).toString().toUtf8());
}
else {
RDApplication::syslog(rd_config,LOG_WARNING,
"failed to start JACK Client \"%s\" [%s]",
(const char *)q->value(0).toString().toUtf8(),
(const char *)q->value(1).toString().toUtf8());
}
sleep(1);
}
delete q;
#endif // JACK
}
void MainObject::jackInit(RDStation *station)
{
#ifdef JACK
jack_options_t jackopts=JackNullOption;
jack_status_t jackstat=JackFailure;
jack_connected=false;
jack_activated=false;
//
// Get Next Available Card Number
//
for(jack_card=0;jack_card<RD_MAX_CARDS;jack_card++) {
if(cae_driver[jack_card]==RDStation::None) {
break;
}
}
if(jack_card==RD_MAX_CARDS) {
RDApplication::syslog(rd_config,LOG_INFO,"no more RD cards available");
return;
}
QString name=QString().sprintf("rivendell_%d",jack_card);
//
// Start Jack Server
//
if(station->startJack()) {
QStringList args=
station->jackCommandLine().split(" ",QString::SkipEmptyParts);
if(args.size()) {
QString program=args.at(0);
args.removeFirst();
QProcess *proc=new QProcess(this);
proc->start(program,args);
if(proc->waitForStarted()) {
RDApplication::syslog(rd_config,LOG_INFO,"JACK server started");
}
else {
RDApplication::syslog(rd_config,LOG_WARNING,
"failed to start JACK server");
}
sleep(1);
}
else {
RDApplication::syslog(rd_config,LOG_WARNING,
"could not start JACK server: no command line specified");
}
}
//
// Attempt to Connect to Jack Server
//
jackopts=JackNoStartServer;
if(station->jackServerName().isEmpty()) {
jack_client=jack_client_open(name,jackopts,&jackstat);
}
else {
jack_client=jack_client_open(name,jackopts,&jackstat,
(const char *)station->jackServerName());
}
if(jack_client==NULL) {
if((jackstat&JackInvalidOption)!=0) {
fprintf (stderr, "invalid or unsupported JACK option\n");
RDApplication::syslog(rd_config,LOG_WARNING,
"invalid or unsupported JACK option");
}
if((jackstat&JackServerError)!=0) {
fprintf (stderr, "communication error with the JACK server\n");
RDApplication::syslog(rd_config,LOG_WARNING,
"communication error with the JACK server");
}
if((jackstat&JackNoSuchClient)!=0) {
fprintf (stderr, "requested JACK client does not exist\n");
RDApplication::syslog(rd_config,LOG_WARNING,
"requested JACK client does not exist");
}
if((jackstat&JackLoadFailure)!=0) {
fprintf (stderr, "unable to load internal JACK client\n");
RDApplication::syslog(rd_config,LOG_WARNING,
"unable to load internal JACK client");
}
if((jackstat&JackInitFailure)!=0) {
fprintf (stderr, "unable to initialize JACK client\n");
RDApplication::syslog(rd_config,LOG_WARNING,
"unable to initialize JACK client");
}
if((jackstat&JackShmFailure)!=0) {
fprintf (stderr, "unable to access JACK shared memory\n");
RDApplication::syslog(rd_config,LOG_WARNING,
"unable to access JACK shared memory");
}
if((jackstat&JackVersionError)!=0) {
fprintf (stderr, "JACK protocol version mismatch\n");
RDApplication::syslog(rd_config,LOG_WARNING,
"JACK protocol version mismatch");
}
if((jackstat&JackServerStarted)!=0) {
fprintf (stderr, "JACK server started\n");
RDApplication::syslog(rd_config,LOG_WARNING,"JACK server started");
}
if((jackstat&JackServerFailed)!=0) {
fprintf (stderr, "unable to communication with JACK server\n");
RDApplication::syslog(rd_config,LOG_WARNING,
"unable to communicate with JACK server");
}
if((jackstat&JackNameNotUnique)!=0) {
fprintf (stderr, "JACK client name not unique\n");
RDApplication::syslog(rd_config,LOG_WARNING,
"JACK client name not unique");
}
if((jackstat&JackFailure)!=0) {
fprintf (stderr, "JACK general failure\n");
RDApplication::syslog(rd_config,LOG_WARNING,"JACK general failure");
}
jack_card=-1;
fprintf (stderr, "no connection to JACK server\n");
RDApplication::syslog(rd_config,LOG_WARNING,"no connection to JACK server");
return;
}
jack_connected=true;
jack_set_process_callback(jack_client,JackProcess,0);
jack_set_sample_rate_callback(jack_client,JackSampleRate,0);
//jack_set_port_connect_callback(jack_client,JackPortConnectCB,this);
#ifdef HAVE_JACK_INFO_SHUTDOWN
jack_on_info_shutdown(jack_client,JackInfoShutdown,0);
#else
jack_on_shutdown(jack_client,JackShutdown,0);
#endif // HAVE_JACK_INFO_SHUTDOWN
RDApplication::syslog(rd_config,LOG_INFO,"connected to JACK server");
//
// Start JACK Clients
//
jack_client_start_timer=new QTimer(this);
connect(jack_client_start_timer,SIGNAL(timeout()),
this,SLOT(jackClientStartData()));
jack_client_start_timer->start(6000,true);
//
// Tell the database about us
//
if(jack_connected) {
station->setCardDriver(jack_card,RDStation::Jack);
station->setCardName(jack_card,"JACK Audio Connection Kit");
station->setCardInputs(jack_card,RD_MAX_PORTS);
station->setCardOutputs(jack_card,RD_MAX_PORTS);
}
//
// Initialize Data Structures
//
for(int i=0;i<RD_MAX_STREAMS;i++) {
for(int j=0;j<RD_MAX_PORTS;j++) {
jack_output_volume_db[j][i]=0;
jack_samples_recorded[i]=0;
}
jack_st_conv[i]=NULL;
}
for(int i=0;i<RD_MAX_PORTS;i++) {
jack_input_volume_db[i]=0;
for(int j=0;j<RD_MAX_PORTS;j++) {
jack_passthrough_volume_db[j][i]=-10000;
}
}
for(int i=0;i<RD_MAX_CARDS;i++) {
for(int j=0;j<RD_MAX_PORTS;j++) {
jack_input_mode[i][j]=0;
}
}
jack_card_process = jack_card; // populate variable used by callback process
//
// Stop & Fade Timers
//
QSignalMapper *stop_mapper=new QSignalMapper(this);
connect(stop_mapper,SIGNAL(mapped(int)),this,SLOT(jackStopTimerData(int)));
QSignalMapper *fade_mapper=new QSignalMapper(this);
connect(fade_mapper,SIGNAL(mapped(int)),this,SLOT(jackFadeTimerData(int)));
QSignalMapper *record_mapper=new QSignalMapper(this);
connect(record_mapper,SIGNAL(mapped(int)),
this,SLOT(jackRecordTimerData(int)));
for(int i=0;i<RD_MAX_STREAMS;i++) {
jack_stop_timer[i]=new QTimer(this);
stop_mapper->setMapping(jack_stop_timer[i],i);
connect(jack_stop_timer[i],SIGNAL(timeout()),stop_mapper,SLOT(map()));
jack_fade_timer[i]=new QTimer(this);
fade_mapper->setMapping(jack_fade_timer[i],i);
connect(jack_fade_timer[i],SIGNAL(timeout()),fade_mapper,SLOT(map()));
}
for(int i=0;i<RD_MAX_PORTS;i++) {
jack_record_timer[i]=new QTimer(this);
record_mapper->setMapping(jack_record_timer[i],i);
connect(jack_record_timer[i],SIGNAL(timeout()),record_mapper,SLOT(map()));
}
//
// Register Ports
//
for(int i=0;i<RD_MAX_PORTS;i++) {
for(int j=0;j<2;j++) {
jack_output_port[i][j]=NULL;
jack_input_port[i][j]=NULL;
}
}
for(int i=0;i<station->jackPorts();i++) {
name=QString().sprintf("playout_%dL",i);
jack_output_port[i][0]=
jack_port_register(jack_client,(const char *)name,
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsOutput|JackPortIsTerminal,0);
name=QString().sprintf("playout_%dR",i);
jack_output_port[i][1]=
jack_port_register(jack_client,(const char *)name,
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsOutput|JackPortIsTerminal,0);
name=QString().sprintf("record_%dL",i);
jack_input_port[i][0]=
jack_port_register(jack_client,(const char *)name,
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsInput|JackPortIsTerminal,0);
name=QString().sprintf("record_%dR",i);
jack_input_port[i][1]=
jack_port_register(jack_client,(const char *)name,
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsInput|JackPortIsTerminal,0);
}
//
// Allocate Temporary Buffers
//
JackInitCallback();
jack_wave_buffer=new short[RINGBUFFER_SIZE];
jack_wave32_buffer=new int[RINGBUFFER_SIZE];
jack_wave24_buffer=new uint8_t[RINGBUFFER_SIZE];
jack_sample_buffer=new jack_default_audio_sample_t[RINGBUFFER_SIZE];
//
// Join the Graph
//
if(jack_activate(jack_client)) {
return;
}
jack_sample_rate=jack_get_sample_rate(jack_client);
if(jack_sample_rate!=system_sample_rate) {
fprintf (stderr,"JACK sample rate mismatch!\n");
RDApplication::syslog(rd_config,LOG_WARNING,"JACK sample rate mismatch!");
}
jack_activated=true;
cae_driver[jack_card]=RDStation::Jack;
JackSessionSetup();
#endif // JACK
}
void MainObject::jackFree()
{
#ifdef JACK
for(int i=0;i<jack_clients.size();i++) {
jack_clients[i]->kill();
delete jack_clients[i];
}
jack_clients.clear();
if(jack_activated) {
jack_deactivate(jack_client);
}
#endif // JACK
}
bool MainObject::jackLoadPlayback(int card,QString wavename,int *stream)
{
#ifdef JACK
if((*stream=GetJackOutputStream())<0) {
RDApplication::syslog(rd_config,LOG_DEBUG,
"jackLoadPlayback(%s) GetJackOutputStream():%d <0",
(const char *)wavename.toUtf8(),*stream);
return false;
}
jack_play_wave[*stream]=new RDWaveFile(wavename);
if(!jack_play_wave[*stream]->openWave()) {
RDApplication::syslog(rd_config,LOG_DEBUG,
"jackLoadPlayback(%s) openWave() failed to open file",
(const char *)wavename.toUtf8());
delete jack_play_wave[*stream];
jack_play_wave[*stream]=NULL;
FreeJackOutputStream(*stream);
*stream=-1;
return false;
}
switch(jack_play_wave[*stream]->getFormatTag()) {
case WAVE_FORMAT_PCM:
case WAVE_FORMAT_VORBIS:
break;
case WAVE_FORMAT_MPEG:
InitMadDecoder(card,*stream,jack_play_wave[*stream]);
break;
default:
RDApplication::syslog(rd_config,LOG_DEBUG,
"jackLoadPlayback(%s) getFormatTag()%d || getBistsPerSample()%d failed",
(const char *) wavename.toUtf8(),
jack_play_wave[*stream]->getFormatTag(),
jack_play_wave[*stream]->getBitsPerSample());
delete jack_play_wave[*stream];
jack_play_wave[*stream]=NULL;
FreeJackOutputStream(*stream);
*stream=-1;
return false;
}
jack_output_channels[*stream]=jack_play_wave[*stream]->getChannels();
jack_output_sample_rate[*stream]=jack_play_wave[*stream]->getSamplesPerSec();
jack_stopping[*stream]=false;
jack_offset[*stream]=0;
jack_output_pos[*stream]=0;
jack_eof[*stream]=false;
FillJackOutputStream(*stream);
return true;
#else
return false;
#endif // JACK
}
bool MainObject::jackUnloadPlayback(int card,int stream)
{
#ifdef JACK
if ((stream <0) || (stream >= RD_MAX_STREAMS)){
return false;
}
if(jack_play_ring[stream]==NULL) {
return false;
}
jack_playing[stream]=false;
switch(jack_play_wave[stream]->getFormatTag()) {
case WAVE_FORMAT_MPEG:
FreeMadDecoder(card,stream);
break;
}
jack_play_wave[stream]->closeWave();
delete jack_play_wave[stream];
jack_play_wave[stream]=NULL;
FreeJackOutputStream(stream);
return true;
#else
return false;
#endif // JACK
}
bool MainObject::jackPlaybackPosition(int card,int stream,unsigned pos)
{
#ifdef JACK
unsigned offset=0;
if ((stream <0) || (stream >= RD_MAX_STREAMS)){
return false;
}
jack_eof[stream]=false;
jack_play_ring[stream]->reset();
switch(jack_play_wave[stream]->getFormatTag()) {
case WAVE_FORMAT_PCM:
case WAVE_FORMAT_VORBIS:
offset=(unsigned)((double)jack_play_wave[stream]->getSamplesPerSec()*
(double)jack_play_wave[stream]->getBlockAlign()*
(double)pos/1000);
jack_offset[stream]=offset/jack_play_wave[stream]->getBlockAlign();
offset=jack_offset[stream]*jack_play_wave[stream]->getBlockAlign();
break;
case WAVE_FORMAT_MPEG:
offset=(unsigned)((double)jack_play_wave[stream]->getSamplesPerSec()*
(double)pos/1000);
jack_offset[stream]=offset/1152*1152;
offset=jack_offset[stream]/1152*jack_play_wave[stream]->getBlockAlign();
FreeMadDecoder(jack_card,stream);
InitMadDecoder(jack_card,stream,jack_play_wave[stream]);
break;
}
if(jack_offset[stream]>(int)jack_play_wave[stream]->getSampleLength()) {
return false;
}
jack_output_pos[stream]=0;
jack_play_wave[stream]->seekWave(offset,SEEK_SET);
FillJackOutputStream(stream);
if(jack_playing[stream]) {
jack_stop_timer[stream]->stop();
jack_stop_timer[stream]->
start(jack_play_wave[stream]->getExtTimeLength()-pos,true);
}
return true;
#else
return false;
#endif // JACK
}
bool MainObject::jackPlay(int card,int stream,int length,int speed,bool pitch,
bool rates)
{
#ifdef JACK
if((stream <0) || (stream >= RD_MAX_STREAMS) ||
(jack_play_ring[stream]==NULL)||jack_playing[stream]) {
return false;
}
if(speed!=RD_TIMESCALE_DIVISOR) {
jack_st_conv[stream]=new soundtouch::SoundTouch();
jack_st_conv[stream]->setTempo((float)speed/RD_TIMESCALE_DIVISOR);
jack_st_conv[stream]->setSampleRate(jack_output_sample_rate[stream]);
jack_st_conv[stream]->setChannels(jack_output_channels[stream]);
}
jack_playing[stream]=true;
if(length>0) {
jack_stop_timer[stream]->start(length,true);
}
statePlayUpdate(card,stream,1);
return true;
#else
return false;
#endif // JACK
}
bool MainObject::jackStopPlayback(int card,int stream)
{
#ifdef JACK
if((stream <0) || (stream>=RD_MAX_STREAMS) ||
(jack_play_ring[stream]==NULL)||(!jack_playing[stream])) {
return false;
}
jack_playing[stream]=false;
jack_stop_timer[stream]->stop();
statePlayUpdate(card,stream,2);
return true;
#else
return false;
#endif // JACK
}
bool MainObject::jackTimescaleSupported(int card)
{
#ifdef JACK
return true;
#else
return false;
#endif // JACK
}
bool MainObject::jackLoadRecord(int card,int stream,int coding,int chans,
int samprate,int bitrate,QString wavename)
{
#ifdef JACK
jack_record_wave[stream]=new RDWaveFile(wavename);
switch(coding) {
case 0: // PCM16
jack_record_wave[stream]->setFormatTag(WAVE_FORMAT_PCM);
jack_record_wave[stream]->setChannels(chans);
jack_record_wave[stream]->setSamplesPerSec(samprate);
jack_record_wave[stream]->setBitsPerSample(16);
break;
case 4: // PCM24
jack_record_wave[stream]->setFormatTag(WAVE_FORMAT_PCM);
jack_record_wave[stream]->setChannels(chans);
jack_record_wave[stream]->setSamplesPerSec(samprate);
jack_record_wave[stream]->setBitsPerSample(24);
break;
case 2: // MPEG Layer 2
if(!InitTwoLameEncoder(card,stream,chans,samprate,bitrate)) {
delete jack_record_wave[stream];
jack_record_wave[stream]=NULL;
return false;
}
jack_record_wave[stream]->setFormatTag(WAVE_FORMAT_MPEG);
jack_record_wave[stream]->setChannels(chans);
jack_record_wave[stream]->setSamplesPerSec(samprate);
jack_record_wave[stream]->setBitsPerSample(16);
jack_record_wave[stream]->setHeadLayer(ACM_MPEG_LAYER2);
switch(chans) {
case 1:
jack_record_wave[stream]->setHeadMode(ACM_MPEG_SINGLECHANNEL);
break;
case 2:
jack_record_wave[stream]->setHeadMode(ACM_MPEG_STEREO);
break;
default:
RDApplication::syslog(rd_config,LOG_WARNING,
"requested unsupported channel count %d, card: %d, stream: %d",
chans,card,stream);
delete jack_record_wave[stream];
jack_record_wave[stream]=NULL;
return false;
}
jack_record_wave[stream]->setHeadBitRate(bitrate);
jack_record_wave[stream]->setMextChunk(true);
jack_record_wave[stream]->setMextHomogenous(true);
jack_record_wave[stream]->setMextPaddingUsed(false);
jack_record_wave[stream]->setMextHackedBitRate(true);
jack_record_wave[stream]->setMextFreeFormat(false);
jack_record_wave[stream]->
setMextFrameSize(144*jack_record_wave[stream]->getHeadBitRate()/
jack_record_wave[stream]->getSamplesPerSec());
jack_record_wave[stream]->setMextAncillaryLength(5);
jack_record_wave[stream]->setMextLeftEnergyPresent(true);
if(chans>1) {
jack_record_wave[stream]->setMextRightEnergyPresent(true);
}
else {
jack_record_wave[stream]->setMextRightEnergyPresent(false);
}
jack_record_wave[stream]->setMextPrivateDataPresent(false);
break;
default:
RDApplication::syslog(rd_config,LOG_WARNING,
"requested invalid audio encoding %d, card: %d, stream: %d",
coding,card,stream);
delete jack_record_wave[stream];
jack_record_wave[stream]=NULL;
return false;
}
jack_record_wave[stream]->setBextChunk(true);
jack_record_wave[stream]->setLevlChunk(true);
if(!jack_record_wave[stream]->createWave()) {
delete jack_record_wave[stream];
jack_record_wave[stream]=NULL;
return false;
}
chown((const char *)wavename,rd_config->uid(),rd_config->gid());
jack_input_channels[stream]=chans;
jack_record_ring[stream]=new RDRingBuffer(RINGBUFFER_SIZE);
jack_record_ring[stream]->reset();
jack_ready[stream]=true;
return true;
/*
if ((stream <0) || (stream >=RD_MAX_PORTS)){
return false;
}
jack_record_wave[stream]=new RDWaveFile(wavename);
jack_record_wave[stream]->setFormatTag(WAVE_FORMAT_PCM);
jack_record_wave[stream]->setChannels(chans);
jack_record_wave[stream]->setSamplesPerSec(samprate);
jack_record_wave[stream]->setBitsPerSample(16);
jack_record_wave[stream]->setBextChunk(true);
jack_record_wave[stream]->setLevlChunk(true);
if(!jack_record_wave[stream]->createWave()) {
delete jack_record_wave[stream];
jack_record_wave[stream]=NULL;
return false;
}
chown((const char *)wavename,rd_config->uid(),rd_config->gid());
jack_input_channels[stream]=chans;
jack_record_ring[stream]=new RDRingBuffer(RINGBUFFER_SIZE);
jack_record_ring[stream]->reset();
jack_ready[stream]=true;
return true;
*/
#else
return false;
#endif // JACK
}
bool MainObject::jackUnloadRecord(int card,int stream,unsigned *len)
{
#ifdef JACK
if ((stream <0) || (stream >= RD_MAX_PORTS)){
return false;
}
jack_recording[stream]=false;
jack_ready[stream]=false;
EmptyJackInputStream(stream,true);
*len=jack_samples_recorded[stream];
jack_samples_recorded[stream]=0;
jack_record_wave[stream]->closeWave(*len);
delete jack_record_wave[stream];
jack_record_wave[stream]=NULL;
delete jack_record_ring[stream];
jack_record_ring[stream]=NULL;
FreeTwoLameEncoder(card,stream);
return true;
#else
return false;
#endif // JACK
}
bool MainObject::jackRecord(int card,int stream,int length,int thres)
{
#ifdef JACK
if ((stream <0) || (stream >= RD_MAX_PORTS)){
return false;
}
if(!jack_ready[stream]) {
return false;
}
jack_recording[stream]=true;
if(jack_input_vox[stream]==0.0) {
if(length>0) {
jack_record_timer[stream]->start(length,true);
}
stateRecordUpdate(card,stream,4);
}
return true;
#else
return false;
#endif // JACK
}
bool MainObject::jackStopRecord(int card,int stream)
{
#ifdef JACK
if ((stream <0) || (stream >= RD_MAX_PORTS)){
return false;
}
if(!jack_recording[stream]) {
return false;
}
jack_recording[stream]=false;
return true;
#else
return false;
#endif // JACK
}
bool MainObject::jackSetInputVolume(int card,int stream,int level)
{
#ifdef JACK
if ((stream <0) || (stream >= RD_MAX_STREAMS)){
return false;
}
if(level>-10000) {
jack_input_volume[stream]=
(jack_default_audio_sample_t)pow(10.0,(double)level/2000.0);
jack_input_volume_db[stream]=level;
}
else {
jack_input_volume[stream]=0.0;
jack_input_volume_db[stream]=-10000;
}
return true;
#else
return false;
#endif // JACK
}
bool MainObject::jackSetOutputVolume(int card,int stream,int port,int level)
{
#ifdef JACK
if ((stream <0) ||(stream >= RD_MAX_STREAMS) ||
(port <0) || (port >= RD_MAX_PORTS)){
return false;
}
if(level>-10000) {
jack_output_volume[port][stream]=
(jack_default_audio_sample_t)pow(10.0,(double)level/2000.0);
jack_output_volume_db[port][stream]=level;
}
else {
jack_output_volume[port][stream]=0.0;
jack_output_volume_db[port][stream]=-10000;
}
return true;
#else
return false;
#endif // JACK
}
bool MainObject::jackFadeOutputVolume(int card,int stream,int port,int level,
int length)
{
#ifdef JACK
int diff;
if ((stream <0) ||(stream >= RD_MAX_STREAMS) ||
(port <0) || (port >= RD_MAX_PORTS)){
return false;
}
if(jack_fade_timer[stream]->isActive()) {
jack_fade_timer[stream]->stop();
}
if(level>jack_output_volume_db[port][stream]) {
jack_fade_up[stream]=true;
diff=level-jack_output_volume_db[port][stream];
}
else {
jack_fade_up[stream]=false;
diff=jack_output_volume_db[port][stream]-level;
}
jack_fade_volume_db[stream]=level;
jack_fade_port[stream]=port;
jack_fade_increment[stream]=diff*RD_JACK_FADE_INTERVAL/length;
jack_fade_timer[stream]->start(RD_JACK_FADE_INTERVAL);
return true;
#else
return false;
#endif // JACK
}
bool MainObject::jackSetInputLevel(int card,int port,int level)
{
#ifdef JACK
return true;
#else
return false;
#endif // JACK
}
bool MainObject::jackSetOutputLevel(int card,int port,int level)
{
#ifdef JACK
return true;
#else
return false;
#endif // JACK
}
bool MainObject::jackSetInputMode(int card,int stream,int mode)
{
#ifdef JACK
jack_input_mode[card][stream]=mode;
return true;
#else
return false;
#endif // JACK
}
bool MainObject::jackSetOutputMode(int card,int stream,int mode)
{
#ifdef JACK
return true;
#else
return false;
#endif // JACK
}
bool MainObject::jackSetInputVoxLevel(int card,int stream,int level)
{
#ifdef JACK
return true;
#else
return false;
#endif // JACK
}
bool MainObject::jackSetInputType(int card,int port,int type)
{
#ifdef JACK
return true;
#else
return false;
#endif // JACK
}
bool MainObject::jackGetInputStatus(int card,int port)
{
#ifdef JACK
return true;
#else
return false;
#endif // JACK
}
bool MainObject::jackGetInputMeters(int card,int port,short levels[2])
{
#ifdef JACK
jack_default_audio_sample_t meter;
if ((port <0) || (port >= RD_MAX_PORTS)){
return false;
}
for(int i=0;i<2;i++) {
meter=jack_input_meter[port][i]->average();
if(meter==0.0) {
levels[i]=-10000;
}
else {
levels[i]=(short)(2000.0*log10(meter));
if(levels[i]<-10000) {
levels[i]=-10000;
}
}
}
return true;
#else
return false;
#endif // JACK
}
bool MainObject::jackGetOutputMeters(int card,int port,short levels[2])
{
#ifdef JACK
jack_default_audio_sample_t meter;
if ((port <0) || (port >= RD_MAX_PORTS)){
return false;
}
for(int i=0;i<2;i++) {
meter=jack_output_meter[port][i]->average();
if(meter==0.0) {
levels[i]=-10000;
}
else {
levels[i]=(short)(2000.0*log10(meter));
if(levels[i]<-10000) {
levels[i]=-10000;
}
}
}
return true;
#else
return false;
#endif // JACK
}
bool MainObject::jackGetStreamOutputMeters(int card,int stream,short levels[2])
{
#ifdef JACK
jack_default_audio_sample_t meter;
if ((stream<0) || (stream>=RD_MAX_STREAMS)){
return false;
}
for(int i=0;i<2;i++) {
meter=jack_stream_output_meter[stream][i]->average();
if(meter==0.0) {
levels[i]=-10000;
}
else {
levels[i]=(short)(2000.0*log10(meter));
if(levels[i]<-10000) {
levels[i]=-10000;
}
}
}
return true;
#else
return false;
#endif // JACK
}
void MainObject::jackGetOutputPosition(int card,unsigned *pos)
{
#ifdef JACK
for(int i=0;i<RD_MAX_STREAMS;i++) {
if(jack_play_wave[i]!=NULL) {
pos[i]=1000*((unsigned long long)jack_offset[i]+jack_output_pos[i])/
jack_play_wave[i]->getSamplesPerSec();
}
else {
pos[i]=0;
}
}
#endif // JACK
}
bool MainObject::jackSetPassthroughLevel(int card,int in_port,int out_port,
int level)
{
#ifdef JACK
if ((in_port <0) || (in_port >= RD_MAX_PORTS) ||
(out_port <0) || (out_port >= RD_MAX_PORTS)){
return false;
}
if(level>-10000) {
jack_passthrough_volume[in_port][out_port]=
(jack_default_audio_sample_t)pow(10.0,(double)level/2000.0);
jack_passthrough_volume_db[in_port][out_port]=level;
}
else {
jack_passthrough_volume[in_port][out_port]=0.0;
jack_passthrough_volume_db[in_port][out_port]=-10000;
}
return true;
#else
return false;
#endif // JACK
}
int MainObject::GetJackOutputStream()
{
#ifdef JACK
for(int i=0;i<RD_MAX_STREAMS;i++) {
if(jack_play_ring[i]==NULL) {
jack_play_ring[i]=new RDRingBuffer(RINGBUFFER_SIZE);
return i;
}
}
return -1;
#else
return -1;
#endif
}
void MainObject::FreeJackOutputStream(int stream)
{
#ifdef JACK
if ((stream <0) || (stream >= RD_MAX_STREAMS)){
return;
}
delete jack_play_ring[stream];
jack_play_ring[stream]=NULL;
if(jack_st_conv[stream]!=NULL) {
delete jack_st_conv[stream];
jack_st_conv[stream]=NULL;
}
#else
return;
#endif
}
void MainObject::EmptyJackInputStream(int stream,bool done)
{
#ifdef JACK
if ((stream <0) || (stream >= RD_MAX_STREAMS)){
return;
}
unsigned n=jack_record_ring[stream]->
read((char *)jack_sample_buffer,jack_record_ring[stream]->readSpace());
WriteJackBuffer(stream,jack_sample_buffer,n,done);
#endif // JACK
}
#ifdef JACK
void MainObject::WriteJackBuffer(int stream,jack_default_audio_sample_t *buffer,
unsigned len,bool done)
{
ssize_t s;
unsigned char mpeg[2048];
unsigned frames;
unsigned n;
frames=len/(sizeof(jack_default_audio_sample_t)*
jack_record_wave[stream]->getChannels());
jack_samples_recorded[stream]+=frames;
switch(jack_record_wave[stream]->getFormatTag()) {
case WAVE_FORMAT_PCM:
switch(jack_record_wave[stream]->getBitsPerSample()) {
case 16: // PCM16
n=len/sizeof(jack_default_audio_sample_t);
src_float_to_short_array(buffer,jack_wave_buffer,n);
jack_record_wave[stream]->writeWave(jack_wave_buffer,n*sizeof(short));
break;
case 24: // PCM24
n=len/sizeof(jack_default_audio_sample_t);
src_float_to_int_array(buffer,jack_wave32_buffer,n);
for(unsigned i=0;i<n;i++) {
for(unsigned j=0;j<3;j++) {
jack_wave24_buffer[3*i+j]=((uint8_t *)jack_wave32_buffer)[4*i+j+1];
}
}
jack_record_wave[stream]->writeWave(jack_wave24_buffer,n*3);
break;
}
break;
case WAVE_FORMAT_MPEG:
#ifdef HAVE_TWOLAME
for(unsigned i=0;i<frames;i+=1152) {
if((i+1152)>frames) {
n=frames-i;
}
else {
n=1152;
}
if((s=twolame_encode_buffer_float32_interleaved(
twolame_lameopts[jack_card][stream],
buffer+i*jack_record_wave[stream]->getChannels(),
n,mpeg,2048))>=0) {
jack_record_wave[stream]->writeWave(mpeg,s);
}
else {
RDApplication::syslog(rd_config,LOG_WARNING,
"TwoLAME encode error, card: %d, stream: %d",jack_card,stream);
}
}
if(done) {
if((s=twolame_encode_flush(twolame_lameopts[jack_card][stream],
mpeg,2048))>=0) {
jack_record_wave[stream]->writeWave(mpeg,s);
}
}
#endif // HAVE_TWOLAME
break;
}
}
#endif // JACK
void MainObject::FillJackOutputStream(int stream)
{
#ifdef JACK
int n=0;
unsigned mpeg_frames=0;
unsigned frame_offset=0;
int m=0;
if ((stream <0) || (stream >= RD_MAX_STREAMS)){
return;
}
int free=
jack_play_ring[stream]->writeSpace()/sizeof(jack_default_audio_sample_t)-1;
if((free<=0)||(jack_eof[stream]==true)) {
return;
}
switch(jack_play_wave[stream]->getFormatTag()) {
case WAVE_FORMAT_PCM:
switch(jack_play_wave[stream]->getBitsPerSample()) {
case 16: // PMC16
free=(int)free/jack_output_channels[stream]*jack_output_channels[stream];
n=jack_play_wave[stream]->readWave(jack_wave_buffer,sizeof(short)*free)/
sizeof(short);
if((n!=free)&&(jack_st_conv[stream]==NULL)) {
jack_eof[stream]=true;
jack_stop_timer[stream]->stop();
}
src_short_to_float_array(jack_wave_buffer,jack_sample_buffer,n);
break;
case 24: // PMC24
free=(int)free/jack_output_channels[stream]*jack_output_channels[stream];
n=jack_play_wave[stream]->readWave(jack_wave24_buffer,3*free)/3;
if((n!=free)&&(jack_st_conv[stream]==NULL)) {
jack_eof[stream]=true;
jack_stop_timer[stream]->stop();
}
for(int i=0;i<n;i++) {
for(unsigned j=0;j<3;j++) {
((uint8_t *)jack_wave32_buffer)[4*i+j+1]=jack_wave24_buffer[3*i+j];
}
}
src_int_to_float_array(jack_wave32_buffer,jack_sample_buffer,n);
break;
}
break;
case WAVE_FORMAT_VORBIS:
free=(int)free/jack_output_channels[stream]*jack_output_channels[stream];
n=jack_play_wave[stream]->readWave(jack_wave_buffer,sizeof(short)*free)/
sizeof(short);
if((n!=free)&&(jack_st_conv[stream]==NULL)) {
jack_eof[stream]=true;
jack_stop_timer[stream]->stop();
}
src_short_to_float_array(jack_wave_buffer,jack_sample_buffer,n);
break;
case WAVE_FORMAT_MPEG:
#ifdef HAVE_MAD
mpeg_frames=free/(1152*jack_output_channels[stream]);
free=mpeg_frames*1152*jack_output_channels[stream];
for(unsigned i=0;i<mpeg_frames;i++) {
m=jack_play_wave[stream]->
readWave(mad_mpeg[jack_card][stream]+mad_left_over[jack_card][stream],
mad_frame_size[jack_card][stream]);
if(m==mad_frame_size[jack_card][stream]) {
mad_stream_buffer(&mad_stream[jack_card][stream],
mad_mpeg[jack_card][stream],
m+mad_left_over[jack_card][stream]);
while(mad_frame_decode(&mad_frame[jack_card][stream],
&mad_stream[jack_card][stream])==0) {
mad_synth_frame(&mad_synth[jack_card][stream],
&mad_frame[jack_card][stream]);
n+=(jack_output_channels[stream]*
mad_synth[jack_card][stream].pcm.length);
for(int j=0;j<mad_synth[jack_card][stream].pcm.length;j++) {
for(int k=0;k<mad_synth[jack_card][stream].pcm.channels;k++) {
jack_sample_buffer[frame_offset+
j*mad_synth[jack_card][stream].pcm.channels+k]=
(jack_default_audio_sample_t)
mad_f_todouble(mad_synth[jack_card][stream].pcm.samples[k][j]);
}
}
frame_offset+=(mad_synth[jack_card][stream].pcm.length*
mad_synth[jack_card][stream].pcm.channels);
}
}
else { // End-of-file, read out last samples
memset(mad_mpeg[jack_card][stream]+mad_left_over[jack_card][stream],0,
MAD_BUFFER_GUARD);
mad_stream_buffer(&mad_stream[jack_card][stream],
mad_mpeg[jack_card][stream],
MAD_BUFFER_GUARD+mad_left_over[jack_card][stream]);
if(mad_frame_decode(&mad_frame[jack_card][stream],
&mad_stream[jack_card][stream])==0) {
mad_synth_frame(&mad_synth[jack_card][stream],
&mad_frame[jack_card][stream]);
n+=(jack_output_channels[stream]*
mad_synth[jack_card][stream].pcm.length);
for(int j=0;j<mad_synth[jack_card][stream].pcm.length;j++) {
for(int k=0;k<mad_synth[jack_card][stream].pcm.channels;k++) {
jack_sample_buffer[frame_offset+
j*mad_synth[jack_card][stream].pcm.channels+k]=
(jack_default_audio_sample_t)
mad_f_todouble(mad_synth[jack_card][stream].pcm.samples[k][j]);
}
}
}
jack_eof[stream]=true;
jack_stop_timer[stream]->stop();
continue;
}
mad_left_over[jack_card][stream]=
mad_stream[jack_card][stream].bufend-
mad_stream[jack_card][stream].next_frame;
memmove(mad_mpeg[jack_card][stream],
mad_stream[jack_card][stream].next_frame,
mad_left_over[jack_card][stream]);
}
#endif // HAVE_MAD
break;
}
if(jack_st_conv[stream]==NULL) {
jack_play_ring[stream]->
write((char *)jack_sample_buffer,n*sizeof(jack_default_audio_sample_t));
}
else {
jack_st_conv[stream]->
putSamples(jack_sample_buffer,n/jack_output_channels[stream]);
free=jack_play_ring[stream]->writeSpace()/
(sizeof(jack_default_audio_sample_t)*jack_output_channels[stream])-1;
while((n=jack_st_conv[stream]->
receiveSamples(jack_sample_buffer,free))>0) {
jack_play_ring[stream]->
write((char *)jack_sample_buffer,n*
sizeof(jack_default_audio_sample_t)*
jack_output_channels[stream]);
free=jack_play_ring[stream]->writeSpace()/
(sizeof(jack_default_audio_sample_t)*jack_output_channels[stream])-1;
}
if((jack_st_conv[stream]->numSamples()==0)&&
(jack_st_conv[stream]->numUnprocessedSamples()==0)) {
jack_eof[stream]=true;
jack_stop_timer[stream]->stop();
}
}
#endif // JACK
}
void MainObject::JackClock()
{
#ifdef JACK
for(int i=0;i<RD_MAX_STREAMS;i++) {
if(jack_stopping[i]) {
jack_stopping[i]=false;
statePlayUpdate(jack_card,i,2);
}
if(jack_playing[i]&&((jack_clock_phase%4)==0)) {
FillJackOutputStream(i);
}
}
jack_clock_phase++;
for(int i=0;i<RD_MAX_PORTS;i++) {
if(jack_recording[i]) {
EmptyJackInputStream(i,false);
}
}
#endif // JACK
}
void MainObject::JackSessionSetup()
{
#ifdef JACK
int count=0;
RDProfile *profile=new RDProfile();
profile->setSource(RD_CONF_FILE);
bool src_ok=false;
bool dest_ok=false;
QString src_tag="Source1";
QString dest_tag="Destination1";
QString src=profile->stringValue("JackSession",src_tag,"",&src_ok);
QString dest=profile->stringValue("JackSession",dest_tag,"",&dest_ok);
while(src_ok&&dest_ok) {
if(jack_connect(jack_client,(const char *)src,(const char *)dest)!=0) {
RDApplication::syslog(rd_config,LOG_WARNING,"unable to connect %s to %s",
(const char *)src.toUtf8(),(const char *)dest.toUtf8());
}
count++;
src_tag=QString().sprintf("Source%d",count+1);
dest_tag=QString().sprintf("Destination%d",count+1);
src=profile->stringValue("JackSession",src_tag,"",&src_ok);
dest=profile->stringValue("JackSession",dest_tag,"",&dest_ok);
}
delete profile;
#endif // JACK
}